Partially solving issue 1788: "Crashing during processing of queue"
It also correct a bug of wrong image orientation (was wrong in the File Browser while good in the Editor tab) This patch also introduce several speed optimizations like: - switch between File Browser and Editor tab in Single Editor mode - asynchronous computation of the Batch Queue's thumbnails - quick start of RT even with a huge queue - less GUI overhead when applying a profile to multiple thumbs in the File Browser
This commit is contained in:
@@ -72,7 +72,9 @@ option (BUILD_SHARED "Build rawtherapee with shared libraries" OFF)
|
||||
option (WITH_BZIP "Build with Bzip2 support" ON)
|
||||
option (WITH_MYFILE_MMAP "Build using memory mapped file" ON)
|
||||
option (OPTION_OMP "Build with OpenMP support" ON)
|
||||
option (BUILD_BUNDLE "Self-contained build" OFF)
|
||||
option (PROTECT_VECTORS "Protect critical vectors by custom R/W Mutex, recommanded even if your std::vector is thread safe" ON)
|
||||
option (TRACE_MYRWMUTEX "Trace RT's custom R/W Mutex (Debug builds only); redirecting std::out to a file is strongly recommended!" OFF)
|
||||
option (AUTO_GDK_FLUSH "Use gdk_flush on all gdk_thread_leave other than the GUI thread; set it ON if you experience X Server warning/errors" OFF)
|
||||
|
||||
# set install directories
|
||||
if (WIN32 OR APPLE)
|
||||
@@ -160,6 +162,25 @@ if (NOT BUILD_BUNDLE AND
|
||||
message (FATAL_ERROR "The paths has to be absolute or use -DBUILD_BUNDLE=ON")
|
||||
endif ()
|
||||
|
||||
# MyRWMutex
|
||||
if (PROTECT_VECTORS)
|
||||
add_definitions (-DPROTECT_VECTORS=1)
|
||||
else (PROTECT_VECTORS)
|
||||
add_definitions (-DPROTECT_VECTORS=0)
|
||||
endif (PROTECT_VECTORS)
|
||||
if (TRACE_MYRWMUTEX)
|
||||
# Note: it will be set to 0 for Debug builds (rtgui/guiutils.h)
|
||||
add_definitions (-DTRACE_MYRWMUTEX=1)
|
||||
else (TRACE_MYRWMUTEX)
|
||||
add_definitions (-DTRACE_MYRWMUTEX=0)
|
||||
endif (TRACE_MYRWMUTEX)
|
||||
|
||||
if (AUTO_GDK_FLUSH)
|
||||
add_definitions (-DAUTO_GDK_FLUSH=1)
|
||||
else (AUTO_GDK_FLUSH)
|
||||
add_definitions (-DAUTO_GDK_FLUSH=0)
|
||||
endif (AUTO_GDK_FLUSH)
|
||||
|
||||
# check for libraries
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules (GTK REQUIRED gtk+-2.0>=2.12)
|
||||
|
@@ -40,7 +40,7 @@
|
||||
|
||||
namespace rtengine {
|
||||
|
||||
Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, int deg) {
|
||||
Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh) {
|
||||
|
||||
StdImageSource imgSrc;
|
||||
if (imgSrc.load(fname)) {
|
||||
@@ -48,10 +48,6 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h,
|
||||
}
|
||||
|
||||
ImageIO* img = imgSrc.getImageIO();
|
||||
|
||||
if (deg) {
|
||||
img->rotate(deg);
|
||||
}
|
||||
|
||||
Thumbnail* tpp = new Thumbnail ();
|
||||
|
||||
@@ -607,10 +603,10 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei
|
||||
int rwidth;
|
||||
if (params.coarse.rotate==90 || params.coarse.rotate==270) {
|
||||
rwidth = rheight;
|
||||
rheight = thumbImg->height * rwidth / thumbImg->width;
|
||||
rheight = int(size_t(thumbImg->height) * size_t(rwidth) / size_t(thumbImg->width));
|
||||
}
|
||||
else
|
||||
rwidth = thumbImg->width * rheight / thumbImg->height;
|
||||
rwidth = int(size_t(thumbImg->width) * size_t(rheight) / size_t(thumbImg->height));
|
||||
|
||||
Imagefloat* baseImg = resizeTo<Imagefloat>(rwidth, rheight, interp, thumbImg);
|
||||
|
||||
|
@@ -81,7 +81,7 @@ namespace rtengine {
|
||||
|
||||
static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh, bool rotate);
|
||||
static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, bool rotate);
|
||||
static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, int deg=0);
|
||||
static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh);
|
||||
|
||||
void getCamWB (double& temp, double& green);
|
||||
void getAutoWB (double& temp, double& green);
|
||||
|
@@ -65,6 +65,17 @@ BatchQueue::~BatchQueue ()
|
||||
delete pmenu;
|
||||
}
|
||||
|
||||
void BatchQueue::resizeLoadedQueue() {
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<fd.size(); i++) {
|
||||
fd.at(i)->resize(getThumbnailHeight());
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce the max size of a thumb, since thumb is processed synchronously on adding to queue
|
||||
// leading to very long waiting when adding more images
|
||||
int BatchQueue::calcMaxThumbnailHeight() {
|
||||
@@ -76,23 +87,37 @@ int BatchQueue::getMaxThumbnailHeight() const {
|
||||
return calcMaxThumbnailHeight();
|
||||
}
|
||||
|
||||
void BatchQueue::saveThumbnailHeight (int height) {
|
||||
options.thumbSizeQueue = height;
|
||||
}
|
||||
|
||||
int BatchQueue::getThumbnailHeight () {
|
||||
// The user could have manually forced the option to a too big value
|
||||
return std::max(std::min(options.thumbSizeQueue, 200), 10);
|
||||
}
|
||||
|
||||
void BatchQueue::rightClicked (ThumbBrowserEntryBase* entry) {
|
||||
|
||||
pmenu->popup (3, this->eventTime);
|
||||
}
|
||||
|
||||
void BatchQueue::addEntries ( std::vector<BatchQueueEntry*> &entries, bool head)
|
||||
void BatchQueue::addEntries ( std::vector<BatchQueueEntry*> &entries, bool head, bool save)
|
||||
{
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for( std::vector<BatchQueueEntry*>::iterator entry = entries.begin(); entry != entries.end();entry++ ){
|
||||
(*entry)->setParent (this);
|
||||
(*entry)->resize (std::min(options.thumbSize, getMaxThumbnailHeight())); // batch queue might have smaller, restricted size
|
||||
|
||||
// BatchQueueButtonSet HAVE TO be added before resizing to take them into account
|
||||
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet (*entry);
|
||||
bqbs->setButtonListener (this);
|
||||
(*entry)->addButtonSet (bqbs);
|
||||
|
||||
(*entry)->resize (getThumbnailHeight()); // batch queue might have smaller, restricted size
|
||||
Glib::ustring tempFile = getTempFilenameForParams( (*entry)->filename );
|
||||
|
||||
// recovery save
|
||||
@@ -114,13 +139,11 @@ void BatchQueue::addEntries ( std::vector<BatchQueueEntry*> &entries, bool head)
|
||||
}
|
||||
if ((*entry)->thumbnail)
|
||||
(*entry)->thumbnail->imageEnqueued ();
|
||||
}
|
||||
}
|
||||
|
||||
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet (*entry);
|
||||
bqbs->setButtonListener (this);
|
||||
(*entry)->addButtonSet (bqbs);
|
||||
}
|
||||
saveBatchQueue( );
|
||||
}
|
||||
if (save)
|
||||
saveBatchQueue( );
|
||||
|
||||
redraw();
|
||||
notifyListener (false);
|
||||
@@ -135,6 +158,12 @@ bool BatchQueue::saveBatchQueue( )
|
||||
if (f==NULL)
|
||||
return false;
|
||||
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (fd.size())
|
||||
// The column's header is mandatory (the first line will be skipped when loaded)
|
||||
fprintf(f,"input image full path|param file full path|output image full path|file format|jpeg quality|jpeg subsampling|"
|
||||
@@ -152,186 +181,186 @@ bool BatchQueue::saveBatchQueue( )
|
||||
bqe->saveFormat.saveParams, bqe->forceFormatOpts
|
||||
);
|
||||
}
|
||||
}
|
||||
fclose (f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BatchQueue::loadBatchQueue( )
|
||||
bool BatchQueue::loadBatchQueue( )
|
||||
{
|
||||
{
|
||||
Glib::ustring savedQueueFile;
|
||||
savedQueueFile = options.rtdir+"/batch/queue.csv";
|
||||
FILE *f = safe_g_fopen (savedQueueFile, "rt");
|
||||
|
||||
if (f!=NULL) {
|
||||
char *buffer = new char[1024];
|
||||
unsigned numLoaded=0;
|
||||
// skipping the first line
|
||||
bool firstLine=true;
|
||||
|
||||
// Yes, it's better to get the lock for the whole file reading,
|
||||
// to update the list in one shot without any other concurrent access!
|
||||
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
Glib::ustring savedQueueFile;
|
||||
savedQueueFile = options.rtdir+"/batch/queue.csv";
|
||||
FILE *f = safe_g_fopen (savedQueueFile, "rt");
|
||||
while (fgets (buffer, 1024, f)){
|
||||
|
||||
if (f!=NULL) {
|
||||
char *buffer = new char[1024];
|
||||
unsigned numLoaded=0;
|
||||
// skipping the first line
|
||||
bool firstLine=true;
|
||||
while (fgets (buffer, 1024, f)){
|
||||
if (firstLine) {
|
||||
// skipping the column's title line
|
||||
firstLine=false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (firstLine) {
|
||||
// skipping the column's title line
|
||||
firstLine=false;
|
||||
continue;
|
||||
}
|
||||
size_t pos;
|
||||
Glib::ustring source;
|
||||
Glib::ustring paramsFile;
|
||||
Glib::ustring outputFile;
|
||||
Glib::ustring saveFmt(options.saveFormat.format);
|
||||
int jpegQuality=options.saveFormat.jpegQuality, jpegSubSamp =options.saveFormat.jpegSubSamp;
|
||||
int pngBits =options.saveFormat.pngBits, pngCompression =options.saveFormat.pngCompression;
|
||||
int tiffBits =options.saveFormat.tiffBits, tiffUncompressed=options.saveFormat.tiffUncompressed;
|
||||
int saveParams =options.saveFormat.saveParams;
|
||||
int forceFormatOpts =options.forceFormatOpts;
|
||||
|
||||
size_t pos;
|
||||
Glib::ustring source;
|
||||
Glib::ustring paramsFile;
|
||||
Glib::ustring outputFile;
|
||||
Glib::ustring saveFmt(options.saveFormat.format);
|
||||
int jpegQuality=options.saveFormat.jpegQuality, jpegSubSamp =options.saveFormat.jpegSubSamp;
|
||||
int pngBits =options.saveFormat.pngBits, pngCompression =options.saveFormat.pngCompression;
|
||||
int tiffBits =options.saveFormat.tiffBits, tiffUncompressed=options.saveFormat.tiffUncompressed;
|
||||
int saveParams =options.saveFormat.saveParams;
|
||||
int forceFormatOpts =options.forceFormatOpts;
|
||||
Glib::ustring currLine(buffer);
|
||||
int a = 0;
|
||||
if (currLine.rfind('\n') != Glib::ustring::npos) a++;
|
||||
if (currLine.rfind('\r') != Glib::ustring::npos) a++;
|
||||
if (a)
|
||||
currLine = currLine.substr(0, currLine.length()-a);
|
||||
|
||||
Glib::ustring currLine(buffer);
|
||||
int a = 0;
|
||||
if (currLine.rfind('\n') != Glib::ustring::npos) a++;
|
||||
if (currLine.rfind('\r') != Glib::ustring::npos) a++;
|
||||
if (a)
|
||||
currLine = currLine.substr(0, currLine.length()-a);
|
||||
// Looking for the image's full path
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
source = currLine.substr(0, pos);
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the image's full path
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
source = currLine.substr(0, pos);
|
||||
// Looking for the procparams' full path
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
paramsFile = currLine.substr(0, pos);
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the full output path; if empty, it'll use the template string
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
outputFile = currLine.substr(0, pos);
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the procparams' full path
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
paramsFile = currLine.substr(0, pos);
|
||||
currLine = currLine.substr(pos+1);
|
||||
// No need to bother reading the last options, they will be ignored if outputFile is empty!
|
||||
if (!outputFile.empty()) {
|
||||
|
||||
// Looking for the full output path; if empty, it'll use the template string
|
||||
// Looking for the saving format
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
outputFile = currLine.substr(0, pos);
|
||||
saveFmt = currLine.substr(0, pos);
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// No need to bother reading the last options, they will be ignored if outputFile is empty!
|
||||
if (!outputFile.empty()) {
|
||||
// Looking for the jpeg quality
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
jpegQuality = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the saving format
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
saveFmt = currLine.substr(0, pos);
|
||||
currLine = currLine.substr(pos+1);
|
||||
// Looking for the jpeg subsampling
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
jpegSubSamp = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the jpeg quality
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
jpegQuality = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
// Looking for the png bit depth
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
pngBits = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the jpeg subsampling
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
jpegSubSamp = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
// Looking for the png compression
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
pngCompression = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the png bit depth
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
pngBits = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
// Looking for the tiff bit depth
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
tiffBits = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the png compression
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
pngCompression = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
// Looking for the tiff uncompression
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
tiffUncompressed = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the tiff bit depth
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
tiffBits = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
// Looking out if we have to save the procparams
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
saveParams = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking for the tiff uncompression
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
tiffUncompressed = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
// Looking out if we have to to use the format options
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
forceFormatOpts = atoi(currLine.substr(0, pos).c_str());
|
||||
// currLine = currLine.substr(pos+1);
|
||||
|
||||
// Looking out if we have to save the procparams
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
saveParams = atoi(currLine.substr(0, pos).c_str());
|
||||
currLine = currLine.substr(pos+1);
|
||||
}}}}}}}}}}}}}
|
||||
|
||||
// Looking out if we have to to use the format options
|
||||
pos = currLine.find('|');
|
||||
if (pos != Glib::ustring::npos) {
|
||||
forceFormatOpts = atoi(currLine.substr(0, pos).c_str());
|
||||
// currLine = currLine.substr(pos+1);
|
||||
if( !source.empty() && !paramsFile.empty() ){
|
||||
rtengine::procparams::ProcParams pparams;
|
||||
if( pparams.load( paramsFile ) )
|
||||
continue;
|
||||
|
||||
}}}}}}}}}}}}}
|
||||
::Thumbnail *thumb = cacheMgr->getEntry( source, &pparams );
|
||||
if( thumb ){
|
||||
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create(source, thumb->getType() == FT_Raw, pparams);
|
||||
|
||||
if( !source.empty() && !paramsFile.empty() ){
|
||||
rtengine::procparams::ProcParams pparams;
|
||||
if( pparams.load( paramsFile ) )
|
||||
continue;
|
||||
int prevh = getMaxThumbnailHeight();
|
||||
int prevw = prevh;
|
||||
thumb->getThumbnailSize (prevw, prevh);
|
||||
|
||||
::Thumbnail *thumb = cacheMgr->getEntry( source );
|
||||
if( thumb ){
|
||||
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create(source, thumb->getType() == FT_Raw, pparams);
|
||||
BatchQueueEntry *entry = new BatchQueueEntry(job, pparams,source, prevw, prevh, thumb);
|
||||
entry->setParent(this);
|
||||
|
||||
int prevh = getMaxThumbnailHeight();
|
||||
int prevw = prevh;
|
||||
guint8* prev = NULL;
|
||||
double tmpscale;
|
||||
rtengine::IImage8* img = thumb->processThumbImage(pparams, prevh, tmpscale);
|
||||
if (img) {
|
||||
prevw = img->getWidth();
|
||||
prevh = img->getHeight();
|
||||
prev = new guint8[prevw * prevh * 3];
|
||||
memcpy(prev, img->getData(), prevw * prevh * 3);
|
||||
img->free();
|
||||
}
|
||||
BatchQueueEntry *entry = new BatchQueueEntry(job, pparams,source, prev, prevw, prevh, thumb);
|
||||
entry->setParent(this);
|
||||
entry->resize(options.thumbSize);
|
||||
entry->savedParamsFile = paramsFile;
|
||||
entry->selected = false;
|
||||
entry->outFileName = outputFile;
|
||||
if (!outputFile.empty()) {
|
||||
entry->saveFormat.format = saveFmt;
|
||||
entry->saveFormat.jpegQuality = jpegQuality;
|
||||
entry->saveFormat.jpegSubSamp = jpegSubSamp;
|
||||
entry->saveFormat.pngBits = pngBits;
|
||||
entry->saveFormat.pngCompression = pngCompression;
|
||||
entry->saveFormat.tiffBits = tiffBits;
|
||||
entry->saveFormat.tiffUncompressed = tiffUncompressed!=0;
|
||||
entry->saveFormat.saveParams = saveParams!=0;
|
||||
entry->forceFormatOpts = forceFormatOpts!=0;
|
||||
}
|
||||
else
|
||||
entry->forceFormatOpts = false;
|
||||
fd.push_back(entry);
|
||||
// BatchQueueButtonSet HAVE TO be added before resizing to take them into account
|
||||
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet(entry);
|
||||
bqbs->setButtonListener(this);
|
||||
entry->addButtonSet(bqbs);
|
||||
|
||||
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet(entry);
|
||||
bqbs->setButtonListener(this);
|
||||
entry->addButtonSet(bqbs);
|
||||
numLoaded++;
|
||||
//entry->resize(getThumbnailHeight());
|
||||
entry->savedParamsFile = paramsFile;
|
||||
entry->selected = false;
|
||||
entry->outFileName = outputFile;
|
||||
if (!outputFile.empty()) {
|
||||
entry->saveFormat.format = saveFmt;
|
||||
entry->saveFormat.jpegQuality = jpegQuality;
|
||||
entry->saveFormat.jpegSubSamp = jpegSubSamp;
|
||||
entry->saveFormat.pngBits = pngBits;
|
||||
entry->saveFormat.pngCompression = pngCompression;
|
||||
entry->saveFormat.tiffBits = tiffBits;
|
||||
entry->saveFormat.tiffUncompressed = tiffUncompressed!=0;
|
||||
entry->saveFormat.saveParams = saveParams!=0;
|
||||
entry->forceFormatOpts = forceFormatOpts!=0;
|
||||
}
|
||||
else
|
||||
entry->forceFormatOpts = false;
|
||||
fd.push_back(entry);
|
||||
|
||||
numLoaded++;
|
||||
}
|
||||
}
|
||||
delete [] buffer;
|
||||
fclose(f);
|
||||
}
|
||||
delete [] buffer;
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
redraw();
|
||||
notifyListener(false);
|
||||
|
||||
return !fd.empty();
|
||||
}
|
||||
|
||||
Glib::ustring BatchQueue::getTempFilenameForParams( const Glib::ustring filename )
|
||||
@@ -359,13 +388,13 @@ int cancelItemUI (void* data)
|
||||
}
|
||||
|
||||
void BatchQueue::cancelItems (std::vector<ThumbBrowserEntryBase*>* items) {
|
||||
{
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<items->size(); i++) {
|
||||
for (size_t i=0; i<items->size(); i++) {
|
||||
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
|
||||
if (entry->processing)
|
||||
continue;
|
||||
@@ -382,59 +411,61 @@ void BatchQueue::cancelItems (std::vector<ThumbBrowserEntryBase*>* items) {
|
||||
fd[i]->selected = false;
|
||||
lastClicked = NULL;
|
||||
selected.clear ();
|
||||
|
||||
saveBatchQueue( );
|
||||
}
|
||||
|
||||
saveBatchQueue( );
|
||||
|
||||
redraw ();
|
||||
notifyListener (false);
|
||||
}
|
||||
|
||||
void BatchQueue::headItems (std::vector<ThumbBrowserEntryBase*>* items) {
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
for (int i=items->size()-1; i>=0; i--) {
|
||||
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
|
||||
if (entry->processing)
|
||||
continue;
|
||||
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
|
||||
if (pos!=fd.end() && pos!=fd.begin()) {
|
||||
fd.erase (pos);
|
||||
// find the first item that is not under processing
|
||||
for (pos=fd.begin(); pos!=fd.end(); pos++)
|
||||
if (!(*pos)->processing) {
|
||||
fd.insert (pos, entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (int i=items->size()-1; i>=0; i--) {
|
||||
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
|
||||
if (entry->processing)
|
||||
continue;
|
||||
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
|
||||
if (pos!=fd.end() && pos!=fd.begin()) {
|
||||
fd.erase (pos);
|
||||
// find the first item that is not under processing
|
||||
for (pos=fd.begin(); pos!=fd.end(); pos++)
|
||||
if (!(*pos)->processing) {
|
||||
fd.insert (pos, entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
saveBatchQueue( );
|
||||
}
|
||||
}
|
||||
saveBatchQueue( );
|
||||
|
||||
redraw ();
|
||||
}
|
||||
|
||||
void BatchQueue::tailItems (std::vector<ThumbBrowserEntryBase*>* items) {
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
for (size_t i=0; i<items->size(); i++) {
|
||||
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
|
||||
if (entry->processing)
|
||||
continue;
|
||||
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
|
||||
if (pos!=fd.end()) {
|
||||
fd.erase (pos);
|
||||
fd.push_back (entry);
|
||||
}
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<items->size(); i++) {
|
||||
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
|
||||
if (entry->processing)
|
||||
continue;
|
||||
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
|
||||
if (pos!=fd.end()) {
|
||||
fd.erase (pos);
|
||||
fd.push_back (entry);
|
||||
}
|
||||
saveBatchQueue( );
|
||||
}
|
||||
}
|
||||
saveBatchQueue( );
|
||||
|
||||
redraw ();
|
||||
}
|
||||
@@ -442,13 +473,13 @@ void BatchQueue::tailItems (std::vector<ThumbBrowserEntryBase*>* items) {
|
||||
void BatchQueue::selectAll () {
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::ReaderLock l(entryRW);
|
||||
#endif
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
lastClicked = NULL;
|
||||
selected.clear ();
|
||||
for (size_t i=0; i<fd.size(); i++) {
|
||||
for (size_t i=0; i<fd.size(); i++) {
|
||||
if (fd[i]->processing)
|
||||
continue;
|
||||
fd[i]->selected = true;
|
||||
@@ -459,17 +490,18 @@ void BatchQueue::selectAll () {
|
||||
}
|
||||
|
||||
void BatchQueue::startProcessing () {
|
||||
if (!processing && !fd.empty()) {
|
||||
BatchQueueEntry* next;
|
||||
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
if (!processing) {
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
next = static_cast<BatchQueueEntry*>(fd[0]);
|
||||
// tag it as processing
|
||||
if (!fd.empty()) {
|
||||
BatchQueueEntry* next;
|
||||
|
||||
next = static_cast<BatchQueueEntry*>(fd[0]);
|
||||
// tag it as processing
|
||||
next->processing = true;
|
||||
processing = next;
|
||||
// remove from selection
|
||||
@@ -480,13 +512,17 @@ void BatchQueue::startProcessing () {
|
||||
processing->selected = false;
|
||||
}
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
|
||||
// remove button set
|
||||
next->removeButtonSet ();
|
||||
}
|
||||
|
||||
// start batch processing
|
||||
rtengine::startBatchProcessing (next->job, this, options.tunnelMetaData);
|
||||
queue_draw ();
|
||||
// start batch processing
|
||||
rtengine::startBatchProcessing (next->job, this, options.tunnelMetaData);
|
||||
queue_draw ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,11 +558,11 @@ rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img) {
|
||||
err = img->saveAsJPEG (fname, saveFormat.jpegQuality, saveFormat.jpegSubSamp);
|
||||
img->free ();
|
||||
|
||||
if (err) throw "Unable to save output file";
|
||||
if (err) throw "Unable to save output file";
|
||||
|
||||
if (saveFormat.saveParams) {
|
||||
// We keep the extension to avoid overwriting the profile when we have
|
||||
// the same output filename with different extension
|
||||
// We keep the extension to avoid overwriting the profile when we have
|
||||
// the same output filename with different extension
|
||||
//processing->params.save (removeExtension(fname) + paramFileExtension);
|
||||
processing->params.save (fname + ".out" + paramFileExtension);
|
||||
}
|
||||
@@ -542,11 +578,11 @@ rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img) {
|
||||
// delete from the queue
|
||||
delete processing; processing = NULL;
|
||||
bool queueEmptied=false;
|
||||
{
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
fd.erase (fd.begin());
|
||||
|
||||
@@ -555,8 +591,8 @@ rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img) {
|
||||
queueEmptied=true;
|
||||
}
|
||||
else if (listener && listener->canStartNext ()) {
|
||||
BatchQueueEntry* next = static_cast<BatchQueueEntry*>(fd[0]);
|
||||
// tag it as selected
|
||||
BatchQueueEntry* next = static_cast<BatchQueueEntry*>(fd[0]);
|
||||
// tag it as selected
|
||||
next->processing = true;
|
||||
processing = next;
|
||||
// remove from selection
|
||||
@@ -567,21 +603,34 @@ rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img) {
|
||||
processing->selected = false;
|
||||
}
|
||||
// remove button set
|
||||
{
|
||||
// ButtonSet have Cairo::Surface which might be rendered while we're trying to delete them
|
||||
GThreadLock lock;
|
||||
next->removeButtonSet ();
|
||||
}
|
||||
if (saveBatchQueue( )) {
|
||||
safe_g_remove( processedParams );
|
||||
// Delete all files in directory \batch when finished, just to be sure to remove zombies
|
||||
if( fd.empty() ){
|
||||
std::vector<Glib::ustring> names;
|
||||
Glib::ustring batchdir = options.rtdir+"/batch/";
|
||||
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (batchdir);
|
||||
safe_build_file_list (dir, names, batchdir);
|
||||
for(std::vector<Glib::ustring>::iterator iter=names.begin(); iter != names.end();iter++ )
|
||||
safe_g_remove( *iter );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (saveBatchQueue( )) {
|
||||
safe_g_remove( processedParams );
|
||||
// Delete all files in directory \batch when finished, just to be sure to remove zombies
|
||||
|
||||
// Not sure that locking is necessary, but it should be safer
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
if( fd.empty() ){
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK_RELEASE(l);
|
||||
#endif
|
||||
std::vector<Glib::ustring> names;
|
||||
Glib::ustring batchdir = options.rtdir+"/batch/";
|
||||
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (batchdir);
|
||||
safe_build_file_list (dir, names, batchdir);
|
||||
for(std::vector<Glib::ustring>::iterator iter=names.begin(); iter != names.end();iter++ )
|
||||
safe_g_remove( *iter );
|
||||
}
|
||||
}
|
||||
|
||||
redraw ();
|
||||
notifyListener (queueEmptied);
|
||||
@@ -728,6 +777,7 @@ void BatchQueue::setProgress (double p) {
|
||||
if (processing)
|
||||
processing->progress = p;
|
||||
|
||||
// No need to acquire the GUI, setProgressUI will do it
|
||||
g_idle_add (setProgressUI, this);
|
||||
}
|
||||
|
||||
@@ -751,6 +801,7 @@ struct NLParams {
|
||||
};
|
||||
|
||||
int bqnotifylistenerUI (void* data) {
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
NLParams* params = static_cast<NLParams*>(data);
|
||||
params->listener->queueSizeChanged (params->qsize, params->queueEmptied);
|
||||
delete params;
|
||||
@@ -762,13 +813,19 @@ void BatchQueue::notifyListener (bool queueEmptied) {
|
||||
if (listener) {
|
||||
NLParams* params = new NLParams;
|
||||
params->listener = listener;
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
params->qsize = fd.size();
|
||||
}
|
||||
params->queueEmptied = queueEmptied;
|
||||
g_idle_add (bqnotifylistenerUI, params);
|
||||
}
|
||||
}
|
||||
|
||||
void BatchQueue::redrawNeeded (LWButton* button) {
|
||||
|
||||
GThreadLock lock;
|
||||
queue_draw ();
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@
|
||||
class BatchQueueListener {
|
||||
|
||||
public:
|
||||
virtual ~BatchQueueListener () {}
|
||||
virtual void queueSizeChanged (int qsize, bool queueEmptied) =0;
|
||||
virtual bool canStartNext () =0;
|
||||
};
|
||||
@@ -39,6 +40,8 @@ class BatchQueue : public ThumbBrowserBase,
|
||||
|
||||
protected:
|
||||
int getMaxThumbnailHeight() const;
|
||||
void saveThumbnailHeight (int height);
|
||||
int getThumbnailHeight ();
|
||||
|
||||
BatchQueueEntry* processing; // holds the currently processed image
|
||||
|
||||
@@ -61,15 +64,22 @@ class BatchQueue : public ThumbBrowserBase,
|
||||
BatchQueue ();
|
||||
~BatchQueue ();
|
||||
|
||||
void addEntries (std::vector<BatchQueueEntry*> &entries, bool head=false);
|
||||
void addEntries (std::vector<BatchQueueEntry*> &entries, bool head=false, bool save=true);
|
||||
void cancelItems (std::vector<ThumbBrowserEntryBase*>* items);
|
||||
void headItems (std::vector<ThumbBrowserEntryBase*>* items);
|
||||
void tailItems (std::vector<ThumbBrowserEntryBase*>* items);
|
||||
void selectAll ();
|
||||
|
||||
void startProcessing ();
|
||||
|
||||
bool hasJobs () { return (!fd.empty()); }
|
||||
|
||||
bool hasJobs () {
|
||||
// not sure that this lock is necessary, but it's safer to keep it...
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
return (!fd.empty());
|
||||
}
|
||||
|
||||
rtengine::ProcessingJob* imageReady (rtengine::IImage16* img);
|
||||
void setProgress (double p);
|
||||
@@ -79,7 +89,8 @@ class BatchQueue : public ThumbBrowserBase,
|
||||
|
||||
void setBatchQueueListener (BatchQueueListener* l) { listener = l; }
|
||||
|
||||
void loadBatchQueue ();
|
||||
bool loadBatchQueue ();
|
||||
void resizeLoadedQueue();
|
||||
|
||||
static Glib::ustring calcAutoFileNameBase (const Glib::ustring& origFileName);
|
||||
static int calcMaxThumbnailHeight();
|
||||
|
@@ -27,16 +27,16 @@
|
||||
bool BatchQueueEntry::iconsLoaded(false);
|
||||
Glib::RefPtr<Gdk::Pixbuf> BatchQueueEntry::savedAsIcon;
|
||||
|
||||
BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, guint8* previmg, int prevw, int prevh, Thumbnail* thm)
|
||||
BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, int prevw, int prevh, Thumbnail* thm)
|
||||
: ThumbBrowserEntryBase(fname),
|
||||
opreview(previmg), origpw(prevw), origph(prevh),
|
||||
opreview(NULL), origpw(prevw), origph(prevh), opreviewDone(false),
|
||||
job(pjob), progress(0), outFileName(""), forceFormatOpts(false) {
|
||||
|
||||
thumbnail=thm;
|
||||
params = pparams;
|
||||
|
||||
#ifndef WIN32
|
||||
// The BatchQueueEntryIdleHelper tracks if an entry has been deleted while it was sitting wating for "idle"
|
||||
#if 1 //ndef WIN32
|
||||
// The BatchQueueEntryIdleHelper tracks if an entry has been deleted while it was sitting waiting for "idle"
|
||||
bqih = new BatchQueueEntryIdleHelper;
|
||||
bqih->bqentry = this;
|
||||
bqih->destroyed = false;
|
||||
@@ -55,24 +55,28 @@ BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine:
|
||||
BatchQueueEntry::~BatchQueueEntry () {
|
||||
|
||||
batchQueueEntryUpdater.removeJobs (this);
|
||||
delete [] opreview; opreview=NULL;
|
||||
if (opreview) delete [] opreview; opreview=NULL;
|
||||
if (thumbnail)
|
||||
thumbnail->decreaseRef ();
|
||||
|
||||
#ifndef WIN32
|
||||
if (bqih->pending)
|
||||
bqih->destroyed = true;
|
||||
else
|
||||
delete bqih;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BatchQueueEntry::refreshThumbnailImage () {
|
||||
|
||||
if (!opreview)
|
||||
return;
|
||||
|
||||
batchQueueEntryUpdater.process (opreview, origpw, origph, preh, this); // this will asynchronously land at this.updateImage
|
||||
if (!opreviewDone) {
|
||||
// creating the image buffer first
|
||||
//if (!opreview) opreview = new guint8[(origpw+1) * origph * 3];
|
||||
// this will asynchronously compute the original preview and land at this.updateImage
|
||||
batchQueueEntryUpdater.process (NULL, origpw, origph, preh, this, ¶ms, thumbnail);
|
||||
}
|
||||
else {
|
||||
// this will asynchronously land at this.updateImage
|
||||
batchQueueEntryUpdater.process (opreview, origpw, origph, preh, this);
|
||||
}
|
||||
}
|
||||
|
||||
void BatchQueueEntry::calcThumbnailSize () {
|
||||
@@ -166,8 +170,6 @@ Glib::ustring BatchQueueEntry::getToolTip (int x, int y) {
|
||||
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
struct BQUpdateParam {
|
||||
BatchQueueEntryIdleHelper* bqih;
|
||||
guint8* img;
|
||||
@@ -180,11 +182,13 @@ int updateImageUIThread (void* data) {
|
||||
|
||||
BatchQueueEntryIdleHelper* bqih = params->bqih;
|
||||
|
||||
// If the BQEntry was destroyed meanwhile, remove all the IdleHelper if all entries came through
|
||||
GThreadLock tLock; // Acquire the GUI
|
||||
|
||||
// If the BQEntry was destroyed meanwhile, remove all the IdleHelper if all entries came through
|
||||
if (bqih->destroyed) {
|
||||
if (bqih->pending == 1)
|
||||
delete bqih;
|
||||
else
|
||||
else
|
||||
bqih->pending--;
|
||||
delete [] params->img;
|
||||
delete params;
|
||||
@@ -198,35 +202,29 @@ int updateImageUIThread (void* data) {
|
||||
delete params;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Starts a copy of img->preview via GTK thread
|
||||
void BatchQueueEntry::updateImage (guint8* img, int w, int h) {
|
||||
// TODO: Check for Linux/Mac
|
||||
#ifdef WIN32
|
||||
void BatchQueueEntry::updateImage (guint8* img, int w, int h, int origw, int origh, guint8* newOPreview) {
|
||||
|
||||
// since the update itself is already called in an async thread and there are problem with accessing opreview in thumbbrowserbase,
|
||||
// it's safer to do this synchrously
|
||||
// it's safer to do this synchronously
|
||||
{
|
||||
GThreadLock lock;
|
||||
|
||||
_updateImage(img,w,h);
|
||||
}
|
||||
#else
|
||||
bqih->pending++;
|
||||
|
||||
BQUpdateParam* param = new BQUpdateParam ();
|
||||
param->bqih = bqih;
|
||||
param->img = img;
|
||||
param->w = w;
|
||||
param->h = h;
|
||||
g_idle_add (updateImageUIThread, param);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BatchQueueEntry::_updateImage (guint8* img, int w, int h) {
|
||||
|
||||
if (preh == h) {
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, lockRW);
|
||||
#endif
|
||||
|
||||
prew = w;
|
||||
assert (preview == NULL);
|
||||
preview = new guint8 [prew*preh*3];
|
||||
memcpy (preview, img, prew*preh*3);
|
||||
if (parent)
|
||||
|
@@ -37,6 +37,7 @@ class BatchQueueEntry : public ThumbBrowserEntryBase, public BQEntryUpdateListen
|
||||
guint8* opreview;
|
||||
int origpw, origph;
|
||||
BatchQueueEntryIdleHelper* bqih;
|
||||
bool opreviewDone;
|
||||
static bool iconsLoaded;
|
||||
|
||||
public:
|
||||
@@ -51,7 +52,7 @@ public:
|
||||
SaveFormat saveFormat;
|
||||
bool forceFormatOpts;
|
||||
|
||||
BatchQueueEntry (rtengine::ProcessingJob* job, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, guint8* previmg, int prevw, int prevh, Thumbnail* thm=NULL);
|
||||
BatchQueueEntry (rtengine::ProcessingJob* job, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, int prevw, int prevh, Thumbnail* thm=NULL);
|
||||
~BatchQueueEntry ();
|
||||
|
||||
void refreshThumbnailImage ();
|
||||
@@ -66,7 +67,7 @@ public:
|
||||
virtual Glib::ustring getToolTip (int x, int y);
|
||||
|
||||
// bqentryupdatelistener interface
|
||||
void updateImage (guint8* img, int w, int h);
|
||||
void updateImage (guint8* img, int w, int h, int origw, int origh, guint8* newOPreview);
|
||||
void _updateImage (guint8* img, int w, int h); // inside gtk thread
|
||||
};
|
||||
|
||||
|
@@ -25,6 +25,16 @@
|
||||
#include "../rtengine/safegtk.h"
|
||||
#include "rtimage.h"
|
||||
|
||||
struct BQProcessLoaded {
|
||||
BatchQueue* bq;
|
||||
};
|
||||
|
||||
int processLoadedBatchQueueUIThread (void* data) {
|
||||
|
||||
BatchQueue* bq = static_cast<BatchQueue*>(data);
|
||||
bq->resizeLoadedQueue();
|
||||
return 0;
|
||||
}
|
||||
|
||||
BatchQueuePanel::BatchQueuePanel () {
|
||||
|
||||
@@ -132,7 +142,9 @@ BatchQueuePanel::BatchQueuePanel () {
|
||||
batchQueue->setBatchQueueListener (this);
|
||||
|
||||
show_all ();
|
||||
batchQueue->loadBatchQueue ();
|
||||
if (batchQueue->loadBatchQueue ()) {
|
||||
g_idle_add_full (G_PRIORITY_LOW, processLoadedBatchQueueUIThread, batchQueue, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -27,6 +27,7 @@ using namespace rtengine::procparams;
|
||||
|
||||
BatchToolPanelCoordinator::BatchToolPanelCoordinator (FilePanel* parent) : ToolPanelCoordinator(), parent(parent) {
|
||||
|
||||
blockedUpdate = false;
|
||||
// remove exif panel and iptc panel
|
||||
std::vector<ToolPanel*>::iterator epi = std::find (toolPanels.begin(), toolPanels.end(), exifpanel);
|
||||
if (epi!=toolPanels.end())
|
||||
@@ -56,13 +57,13 @@ void BatchToolPanelCoordinator::selectionChanged (const std::vector<Thumbnail*>&
|
||||
|
||||
void BatchToolPanelCoordinator::closeSession (bool save) {
|
||||
|
||||
pparamsEdited.set (false);
|
||||
pparamsEdited.set (false);
|
||||
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
selected[i]->removeThumbnailListener (this);
|
||||
|
||||
if (somethingChanged && save) {
|
||||
|
||||
|
||||
// read new values from the gui
|
||||
for (size_t i=0; i<toolPanels.size(); i++)
|
||||
toolPanels[i]->write (&pparams, &pparamsEdited);
|
||||
@@ -73,11 +74,11 @@ void BatchToolPanelCoordinator::closeSession (bool save) {
|
||||
newParams = initialPP[i];
|
||||
pparamsEdited.combine (newParams, pparams, selected.size()==1);
|
||||
|
||||
// trim new adjuster's values to the adjuster's limits
|
||||
for (unsigned int j=0; j<toolPanels.size(); j++)
|
||||
toolPanels[j]->trimValues (&newParams);
|
||||
// trim new adjuster's values to the adjuster's limits
|
||||
for (unsigned int j=0; j<toolPanels.size(); j++)
|
||||
toolPanels[j]->trimValues (&newParams);
|
||||
|
||||
selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, true);
|
||||
selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, true);
|
||||
}
|
||||
}
|
||||
for (size_t i=0; i<paramcListeners.size(); i++)
|
||||
@@ -333,12 +334,28 @@ void BatchToolPanelCoordinator::optionsChanged () {
|
||||
|
||||
void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt) {
|
||||
|
||||
if (whoChangedIt!=BATCHEDITOR) {
|
||||
if (whoChangedIt!=BATCHEDITOR && !blockedUpdate) {
|
||||
closeSession (false);
|
||||
initSession ();
|
||||
}
|
||||
}
|
||||
|
||||
void BatchToolPanelCoordinator::beginBatchPParamsChange(int numberOfEntries) {
|
||||
|
||||
blockedUpdate = true;
|
||||
if (numberOfEntries > 50) // Arbitrary amount
|
||||
parent->set_sensitive(false);
|
||||
}
|
||||
|
||||
// The end of a batch pparams change triggers a close/initsession
|
||||
void BatchToolPanelCoordinator::endBatchPParamsChange() {
|
||||
//printf("BatchToolPanelCoordinator::endBatchPParamsChange / Nouvelle session!\n");
|
||||
closeSession (false);
|
||||
initSession ();
|
||||
blockedUpdate = false;
|
||||
parent->set_sensitive(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING: profileChange is actually called by the History only.
|
||||
* Using a Profile panel in the batch tool panel editor is actually
|
||||
|
@@ -30,6 +30,7 @@ class FilePanel;
|
||||
class BatchToolPanelCoordinator :
|
||||
public ToolPanelCoordinator,
|
||||
public FileSelectionChangeListener,
|
||||
public BatchPParamsChangeListener,
|
||||
public ThumbnailListener
|
||||
{
|
||||
protected:
|
||||
@@ -39,6 +40,7 @@ class BatchToolPanelCoordinator :
|
||||
std::vector<Glib::ustring> selFileNames;
|
||||
std::vector<rtengine::procparams::ProcParams> initialPP;
|
||||
bool somethingChanged;
|
||||
bool blockedUpdate;
|
||||
FilePanel* parent;
|
||||
|
||||
void closeSession (bool save=true);
|
||||
@@ -63,7 +65,11 @@ class BatchToolPanelCoordinator :
|
||||
|
||||
// thumbnaillistener interface
|
||||
void procParamsChanged (Thumbnail* thm, int whoChangedIt);
|
||||
|
||||
|
||||
// batchpparamschangelistener interface
|
||||
void beginBatchPParamsChange(int numberOfEntries);
|
||||
void endBatchPParamsChange();
|
||||
|
||||
// imageareatoollistener interface
|
||||
void spotWBselected (int x, int y, Thumbnail* thm=NULL);
|
||||
void cropSelectionReady ();
|
||||
|
@@ -23,12 +23,17 @@
|
||||
BatchQueueEntryUpdater batchQueueEntryUpdater;
|
||||
|
||||
BatchQueueEntryUpdater::BatchQueueEntryUpdater ()
|
||||
: tostop(false), stopped(true), qMutex(NULL) {
|
||||
: tostop(false), stopped(true), thread(NULL), qMutex(NULL) {
|
||||
}
|
||||
|
||||
void BatchQueueEntryUpdater::process (guint8* oimg, int ow, int oh, int newh, BQEntryUpdateListener* listener) {
|
||||
void BatchQueueEntryUpdater::process (guint8* oimg, int ow, int oh, int newh, BQEntryUpdateListener* listener, rtengine::ProcParams* pparams, Thumbnail* thumbnail) {
|
||||
if (!oimg && (!pparams || !thumbnail)) {
|
||||
//printf("WARNING! !oimg && (!pparams || !thumbnail)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qMutex)
|
||||
qMutex = new Glib::Mutex ();
|
||||
qMutex = new Glib::Mutex ();
|
||||
|
||||
qMutex->lock ();
|
||||
// look up if an older version is in the queue
|
||||
@@ -39,6 +44,8 @@ void BatchQueueEntryUpdater::process (guint8* oimg, int ow, int oh, int newh, BQ
|
||||
i->oh = oh;
|
||||
i->newh = newh;
|
||||
i->listener = listener;
|
||||
i->pparams = pparams;
|
||||
i->thumbnail = thumbnail;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -50,6 +57,8 @@ void BatchQueueEntryUpdater::process (guint8* oimg, int ow, int oh, int newh, BQ
|
||||
j.oh = oh;
|
||||
j.newh = newh;
|
||||
j.listener = listener;
|
||||
j.pparams = pparams;
|
||||
j.thumbnail = thumbnail;
|
||||
jqueue.push_back (j);
|
||||
}
|
||||
qMutex->unlock ();
|
||||
@@ -79,11 +88,37 @@ void BatchQueueEntryUpdater::processThread () {
|
||||
}
|
||||
qMutex->unlock ();
|
||||
|
||||
if (!isEmpty && current.listener) {
|
||||
rtengine::IImage8* img = NULL;
|
||||
bool newBuffer = false;
|
||||
if (current.thumbnail && current.pparams) {
|
||||
// the thumbnail and the pparams are provided, it means that we have to build the original preview image
|
||||
double tmpscale;
|
||||
img = current.thumbnail->processThumbImage (*current.pparams, current.oh, tmpscale);
|
||||
//current.thumbnail->decreaseRef (); // WARNING: decreasing refcount (and maybe deleting) thumbnail, with or without processed image
|
||||
if (img) {
|
||||
int prevw = img->getWidth();
|
||||
int prevh = img->getHeight();
|
||||
#ifndef NDEBUG
|
||||
if (current.ow != img->getW() || current.oh != img->getH())
|
||||
printf("WARNING! Expected image size: %dx%d ; image size is: %dx%d\n", current.ow, current.oh, img->getW(), img->getH());
|
||||
assert ((current.ow+1)*current.oh >= img->getW()*img->getH());
|
||||
#endif
|
||||
current.ow = prevw;
|
||||
current.oh = prevh;
|
||||
if (!current.oimg) {
|
||||
current.oimg = new guint8[prevw*prevh*3];
|
||||
newBuffer = true;
|
||||
}
|
||||
memcpy(current.oimg, img->getData(), prevw * prevh * 3);
|
||||
img->free();
|
||||
}
|
||||
}
|
||||
|
||||
if (current.oimg && !isEmpty && current.listener) {
|
||||
int neww = current.newh * current.ow / current.oh;
|
||||
guint8* img = new guint8 [current.newh*neww*3];
|
||||
thumbInterp (current.oimg, current.ow, current.oh, img, neww, current.newh);
|
||||
current.listener->updateImage (img, neww, current.newh);
|
||||
current.listener->updateImage (img, neww, current.newh, current.ow, current.oh, newBuffer?current.oimg:NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,12 +149,11 @@ void BatchQueueEntryUpdater::terminate () {
|
||||
if (!qMutex || stopped) return;
|
||||
|
||||
if (!stopped) {
|
||||
// Yield to currenly running thread and wait till it's finished
|
||||
gdk_threads_leave();
|
||||
tostop = true;
|
||||
// Yield to currently running thread and wait till it's finished
|
||||
GThreadUnLock();
|
||||
tostop = true;
|
||||
Glib::Thread::self()->yield();
|
||||
if (!stopped) thread->join ();
|
||||
gdk_threads_enter();
|
||||
}
|
||||
|
||||
// Remove remaining jobs
|
||||
|
@@ -26,7 +26,8 @@
|
||||
class BQEntryUpdateListener {
|
||||
|
||||
public:
|
||||
virtual void updateImage (guint8* img, int w, int h) {}
|
||||
virtual ~BQEntryUpdateListener () {}
|
||||
virtual void updateImage (guint8* img, int w, int h, int origw, int origh, guint8* newOPreview) {}
|
||||
};
|
||||
|
||||
class BatchQueueEntryUpdater {
|
||||
@@ -35,6 +36,8 @@ class BatchQueueEntryUpdater {
|
||||
guint8* oimg;
|
||||
int ow, oh, newh;
|
||||
BQEntryUpdateListener* listener;
|
||||
rtengine::ProcParams* pparams;
|
||||
Thumbnail* thumbnail;
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -47,7 +50,7 @@ class BatchQueueEntryUpdater {
|
||||
public:
|
||||
BatchQueueEntryUpdater ();
|
||||
|
||||
void process (guint8* oimg, int ow, int oh, int newh, BQEntryUpdateListener* listener);
|
||||
void process (guint8* oimg, int ow, int oh, int newh, BQEntryUpdateListener* listener, rtengine::ProcParams* pparams=NULL, Thumbnail* thumbnail=NULL);
|
||||
void removeJobs (BQEntryUpdateListener* listener);
|
||||
void terminate ();
|
||||
|
||||
|
@@ -33,8 +33,13 @@ int CacheImageData::load (const Glib::ustring& fname) {
|
||||
rtengine::SafeKeyFile keyFile;
|
||||
|
||||
try {
|
||||
if (!keyFile.load_from_file (fname))
|
||||
bool loaded = keyFile.load_from_file (fname);
|
||||
if (!loaded) {
|
||||
#ifndef NDEBUG
|
||||
printf("Failed to load_from_file(%s)\n", fname.c_str());
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (keyFile.has_group ("General")) {
|
||||
if (keyFile.has_key ("General", "MD5")) md5 = keyFile.get_string ("General", "MD5");
|
||||
@@ -58,32 +63,31 @@ int CacheImageData::load (const Glib::ustring& fname) {
|
||||
if (keyFile.has_key ("DateTime", "MSec")) msec = keyFile.get_integer ("DateTime", "MSec");
|
||||
}
|
||||
|
||||
exifValid = false;
|
||||
|
||||
if (keyFile.has_group ("ExifInfo")) {
|
||||
exifValid = true;
|
||||
if (keyFile.has_key ("ExifInfo", "Valid")) exifValid = keyFile.get_boolean ("ExifInfo", "Valid");
|
||||
exifValid = false;
|
||||
|
||||
if (exifValid) {
|
||||
if (keyFile.has_key ("ExifInfo", "FNumber")) fnumber = keyFile.get_double ("ExifInfo", "FNumber");
|
||||
if (keyFile.has_key ("ExifInfo", "Shutter")) shutter = keyFile.get_double ("ExifInfo", "Shutter");
|
||||
if (keyFile.has_key ("ExifInfo", "FocalLen")) focalLen = keyFile.get_double ("ExifInfo", "FocalLen");
|
||||
if (keyFile.has_group ("ExifInfo")) {
|
||||
exifValid = true;
|
||||
if (keyFile.has_key ("ExifInfo", "Valid")) exifValid = keyFile.get_boolean ("ExifInfo", "Valid");
|
||||
|
||||
if (exifValid) {
|
||||
if (keyFile.has_key ("ExifInfo", "FNumber")) fnumber = keyFile.get_double ("ExifInfo", "FNumber");
|
||||
if (keyFile.has_key ("ExifInfo", "Shutter")) shutter = keyFile.get_double ("ExifInfo", "Shutter");
|
||||
if (keyFile.has_key ("ExifInfo", "FocalLen")) focalLen = keyFile.get_double ("ExifInfo", "FocalLen");
|
||||
if (keyFile.has_key ("ExifInfo", "FocalLen35mm")) focalLen35mm = keyFile.get_double ("ExifInfo", "FocalLen35mm");
|
||||
else focalLen35mm=focalLen; // prevent crashes on old files
|
||||
if (keyFile.has_key ("ExifInfo", "FocusDist")) focusDist = keyFile.get_double ("ExifInfo", "FocusDist");
|
||||
else focusDist=0;
|
||||
if (keyFile.has_key ("ExifInfo", "ISO")) iso = keyFile.get_integer ("ExifInfo", "ISO");
|
||||
if (keyFile.has_key ("ExifInfo", "ExpComp")) expcomp = keyFile.get_string ("ExifInfo", "ExpComp");
|
||||
}
|
||||
if (keyFile.has_key ("ExifInfo", "Lens")) lens = keyFile.get_string ("ExifInfo", "Lens");
|
||||
if (keyFile.has_key ("ExifInfo", "Camera")) camera = keyFile.get_string ("ExifInfo", "Camera");
|
||||
}
|
||||
|
||||
if (keyFile.has_group ("FileInfo")) {
|
||||
if (keyFile.has_key ("FileInfo", "Filetype")) filetype = keyFile.get_string ("FileInfo", "Filetype");
|
||||
}
|
||||
|
||||
|
||||
if (keyFile.has_key ("ExifInfo", "ISO")) iso = keyFile.get_integer ("ExifInfo", "ISO");
|
||||
if (keyFile.has_key ("ExifInfo", "ExpComp")) expcomp = keyFile.get_string ("ExifInfo", "ExpComp");
|
||||
}
|
||||
if (keyFile.has_key ("ExifInfo", "Lens")) lens = keyFile.get_string ("ExifInfo", "Lens");
|
||||
if (keyFile.has_key ("ExifInfo", "Camera")) camera = keyFile.get_string ("ExifInfo", "Camera");
|
||||
}
|
||||
|
||||
if (keyFile.has_group ("FileInfo")) {
|
||||
if (keyFile.has_key ("FileInfo", "Filetype")) filetype = keyFile.get_string ("FileInfo", "Filetype");
|
||||
}
|
||||
|
||||
if (format==FT_Raw && keyFile.has_group ("ExtraRawInfo")) {
|
||||
if (keyFile.has_key ("ExtraRawInfo", "ThumbImageType")) thumbImgType = keyFile.get_integer ("ExtraRawInfo", "ThumbImageType");
|
||||
if (keyFile.has_key ("ExtraRawInfo", "ThumbImageOffset")) thumbOffset = keyFile.get_integer ("ExtraRawInfo", "ThumbImageOffset");
|
||||
@@ -94,9 +98,10 @@ int CacheImageData::load (const Glib::ustring& fname) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
catch (Glib::Error) {
|
||||
return 1;
|
||||
catch (Glib::Error &err) {
|
||||
printf("Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CacheImageData::save (const Glib::ustring& fname) {
|
||||
@@ -151,5 +156,6 @@ int CacheImageData::save (const Glib::ustring& fname) {
|
||||
fprintf (f, "%s", keyFile.to_data().c_str());
|
||||
fclose (f);
|
||||
return 0;
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -64,7 +64,11 @@ void CacheManager::init () {
|
||||
safe_g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "data")), 511);
|
||||
}
|
||||
|
||||
Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) {
|
||||
/*
|
||||
* if pparams is NULL (default), get the ProcParams from the cache;
|
||||
* if pparams is non NULL, compute the thumbnails with the provided pparams
|
||||
*/
|
||||
Thumbnail* CacheManager::getEntry (const Glib::ustring& fname, const rtengine::procparams::ProcParams *pparams) {
|
||||
|
||||
Thumbnail* res = NULL;
|
||||
|
||||
@@ -93,8 +97,8 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) {
|
||||
if (safe_file_test (cfname, Glib::FILE_TEST_EXISTS)) {
|
||||
CacheImageData* cfs = new CacheImageData ();
|
||||
int e = cfs->load (cfname);
|
||||
if (!e && cfs->supported==true)
|
||||
res = new Thumbnail (this, fname, cfs);
|
||||
if (!e && cfs->supported==true)
|
||||
res = new Thumbnail (this, fname, cfs, pparams);
|
||||
if (res && !res->isSupported ()) {
|
||||
delete res;
|
||||
res = NULL;
|
||||
@@ -104,7 +108,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) {
|
||||
|
||||
// if not, create a new one
|
||||
if (!res) {
|
||||
res = new Thumbnail (this, fname, md5);
|
||||
res = new Thumbnail (this, fname, md5, pparams);
|
||||
if (!res->isSupported ()) {
|
||||
delete res;
|
||||
res = NULL;
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include <glibmm.h>
|
||||
#include "thumbnail.h"
|
||||
#include <cstdio>
|
||||
#include "../rtengine/procparams.h"
|
||||
|
||||
class Thumbnail;
|
||||
|
||||
@@ -45,7 +46,7 @@ class CacheManager {
|
||||
static CacheManager* getInstance(void);
|
||||
|
||||
void init ();
|
||||
Thumbnail* getEntry (const Glib::ustring& fname);
|
||||
Thumbnail* getEntry (const Glib::ustring& fname, const rtengine::procparams::ProcParams *pparams=NULL);
|
||||
void deleteEntry (const Glib::ustring& fname);
|
||||
void renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename);
|
||||
|
||||
|
@@ -893,14 +893,14 @@ void ColorAppearance::setDefaults (const ProcParams* defParams, const ParamsEdit
|
||||
}
|
||||
}
|
||||
int autoCamChangedUI (void* data) {
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
(static_cast<ColorAppearance*>(data))->autoCamComputed_ ();
|
||||
return 0;
|
||||
}
|
||||
void ColorAppearance::autoCamChanged (double ccam)
|
||||
{
|
||||
nextCcam = ccam;
|
||||
g_idle_add (autoCamChangedUI, this);
|
||||
// Glib::signal_idle().connect (sigc::mem_fun(*this, &ColorAppearance::autoCamComputed_));
|
||||
g_idle_add (autoCamChangedUI, this);
|
||||
}
|
||||
|
||||
bool ColorAppearance::autoCamComputed_ () {
|
||||
@@ -913,14 +913,14 @@ bool ColorAppearance::autoCamComputed_ () {
|
||||
return false;
|
||||
}
|
||||
int adapCamChangedUI (void* data) {
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
(static_cast<ColorAppearance*>(data))->adapCamComputed_ ();
|
||||
return 0;
|
||||
}
|
||||
void ColorAppearance::adapCamChanged (double cadap)
|
||||
{
|
||||
nextCadap = cadap;
|
||||
g_idle_add (adapCamChangedUI, this);
|
||||
// Glib::signal_idle().connect (sigc::mem_fun(*this, &ColorAppearance::autoCamComputed_));
|
||||
g_idle_add (adapCamChangedUI, this);
|
||||
}
|
||||
|
||||
bool ColorAppearance::adapCamComputed_ () {
|
||||
|
@@ -469,11 +469,13 @@ void Crop::enabledChanged () {
|
||||
}
|
||||
|
||||
int notifyListenerUI (void* data) {
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
(static_cast<Crop*>(data))->notifyListener ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int refreshSpinsUI (void* data) {
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
RefreshSpinHelper* rsh = static_cast<RefreshSpinHelper*>(data);
|
||||
rsh->crop->refreshSpins (rsh->notify);
|
||||
delete rsh;
|
||||
@@ -587,23 +589,23 @@ void Crop::ratioChanged () {
|
||||
|
||||
// Correct current crop if it doesn't fit
|
||||
void Crop::adjustCropToRatio() {
|
||||
if (fixr->get_active() && !fixr->get_inconsistent()) {
|
||||
if (fixr->get_active() && !fixr->get_inconsistent()) {
|
||||
|
||||
// int W = w->get_value ();
|
||||
// int H = h->get_value ();
|
||||
int W = nw;
|
||||
int H = nh;
|
||||
int X = nx;
|
||||
int Y = ny;
|
||||
if (W>=H)
|
||||
cropWidth2Resized (X, Y, W, H);
|
||||
else
|
||||
cropHeight2Resized (X, Y, W, H);
|
||||
// int W = w->get_value ();
|
||||
// int H = h->get_value ();
|
||||
int W = nw;
|
||||
int H = nh;
|
||||
int X = nx;
|
||||
int Y = ny;
|
||||
if (W>=H)
|
||||
cropWidth2Resized (X, Y, W, H);
|
||||
else
|
||||
cropHeight2Resized (X, Y, W, H);
|
||||
}
|
||||
|
||||
// This will safe the options
|
||||
// This will save the options
|
||||
g_idle_add (refreshSpinsUI, new RefreshSpinHelper (this, true));
|
||||
}
|
||||
}
|
||||
|
||||
void Crop::refreshSize () {
|
||||
|
||||
@@ -667,6 +669,7 @@ struct setdimparams {
|
||||
};
|
||||
|
||||
int sizeChangedUI (void* data) {
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
setdimparams* params = static_cast<setdimparams*>(data);
|
||||
params->crop->setDimensions (params->x, params->y);
|
||||
delete params;
|
||||
@@ -958,12 +961,11 @@ void Crop::cropResized (int &x, int &y, int& x2, int& y2) {
|
||||
nh = H;
|
||||
|
||||
g_idle_add (refreshSpinsUI, new RefreshSpinHelper (this, false));
|
||||
// Glib::signal_idle().connect (sigc::mem_fun(*this, &Crop::refreshSpins));
|
||||
}
|
||||
|
||||
void Crop::cropManipReady () {
|
||||
|
||||
g_idle_add (notifyListenerUI, this);
|
||||
g_idle_add (notifyListenerUI, this);
|
||||
}
|
||||
|
||||
double Crop::getRatio () {
|
||||
|
@@ -186,11 +186,11 @@ int createpixbufs (void* data) {
|
||||
if (!ch->enabled) {
|
||||
delete [] ch->cropimg;
|
||||
ch->cropimg = NULL;
|
||||
delete [] ch->cropimgtrue;
|
||||
delete [] ch->cropimgtrue;
|
||||
ch->cropimgtrue = NULL;
|
||||
ch->cimg.unlock ();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch->cropimg) {
|
||||
if (ch->cix==ch->cropX && ch->ciy==ch->cropY && ch->ciw==ch->cropW && ch->cih==ch->cropH && ch->cis==(ch->zoom>=1000?1:ch->zoom)) {
|
||||
@@ -207,15 +207,15 @@ int createpixbufs (void* data) {
|
||||
ch->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh);
|
||||
tmpPixbuf->scale (ch->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom/1000.0, czoom/1000.0, Gdk::INTERP_NEAREST);
|
||||
tmpPixbuf.clear ();
|
||||
|
||||
Glib::RefPtr<Gdk::Pixbuf> tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2*ch->cropimg_height, 3*ch->cropimg_width);
|
||||
|
||||
Glib::RefPtr<Gdk::Pixbuf> tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2*ch->cropimg_height, 3*ch->cropimg_width);
|
||||
ch->cropPixbuftrue = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh);
|
||||
tmpPixbuftrue->scale (ch->cropPixbuftrue, 0, 0, imw, imh, 0, 0, czoom/1000.0, czoom/1000.0, Gdk::INTERP_NEAREST);
|
||||
tmpPixbuftrue.clear ();
|
||||
}
|
||||
delete [] ch->cropimg;
|
||||
ch->cropimg = NULL;
|
||||
delete [] ch->cropimgtrue;
|
||||
delete [] ch->cropimgtrue;
|
||||
ch->cropimgtrue = NULL;
|
||||
}
|
||||
ch->cimg.unlock ();
|
||||
@@ -233,7 +233,7 @@ int createpixbufs (void* data) {
|
||||
}
|
||||
|
||||
void CropHandler::setDetailedCrop (IImage8* im, IImage8* imtrue, rtengine::procparams::ColorManagementParams cmp,
|
||||
rtengine::procparams::CropParams cp, int ax, int ay, int aw, int ah, int askip) {
|
||||
rtengine::procparams::CropParams cp, int ax, int ay, int aw, int ah, int askip) {
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
@@ -255,9 +255,9 @@ void CropHandler::setDetailedCrop (IImage8* im, IImage8* imtrue, rtengine::procp
|
||||
cropimg_width = im->getWidth ();
|
||||
cropimg_height = im->getHeight ();
|
||||
cropimg = new unsigned char [3*cropimg_width*cropimg_height];
|
||||
cropimgtrue = new unsigned char [3*cropimg_width*cropimg_height];
|
||||
cropimgtrue = new unsigned char [3*cropimg_width*cropimg_height];
|
||||
memcpy (cropimg, im->getData(), 3*cropimg_width*cropimg_height);
|
||||
memcpy (cropimgtrue, imtrue->getData(), 3*cropimg_width*cropimg_height);
|
||||
memcpy (cropimgtrue, imtrue->getData(), 3*cropimg_width*cropimg_height);
|
||||
cix = ax;
|
||||
ciy = ay;
|
||||
ciw = aw;
|
||||
|
@@ -29,9 +29,12 @@
|
||||
#include "rtimage.h"
|
||||
|
||||
#define CHECKTIME 5000
|
||||
extern Glib::ustring argv0;
|
||||
|
||||
DirBrowser::DirBrowser () {
|
||||
DirBrowser::DirBrowser () : expandSuccess(false)
|
||||
#ifdef WIN32
|
||||
, volumes(0)
|
||||
#endif
|
||||
{
|
||||
|
||||
dirtree = Gtk::manage ( new Gtk::TreeView() );
|
||||
scrolledwindow4 = Gtk::manage ( new Gtk::ScrolledWindow() );
|
||||
@@ -144,7 +147,7 @@ void DirBrowser::updateVolumes () {
|
||||
|
||||
int nvolumes = GetLogicalDrives ();
|
||||
if (nvolumes!=volumes) {
|
||||
GThreadLock lock;
|
||||
GThreadLock lock;
|
||||
|
||||
for (int i=0; i<32; i++)
|
||||
if (((volumes >> i) & 1) && !((nvolumes >> i) & 1)) { // volume i has been deleted
|
||||
@@ -237,23 +240,26 @@ void DirBrowser::updateDir (const Gtk::TreeModel::iterator& iter) {
|
||||
for (Gtk::TreeModel::iterator it=iter->children().begin(); it!=iter->children().end(); it++)
|
||||
if (!safe_file_test (it->get_value (dtColumns.dirname), Glib::FILE_TEST_EXISTS)
|
||||
|| !safe_file_test (it->get_value (dtColumns.dirname), Glib::FILE_TEST_IS_DIR)) {
|
||||
GThreadLock lock;
|
||||
dirTreeModel->erase (it);
|
||||
change = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// test if new files are created
|
||||
std::vector<Glib::ustring> subDirs;
|
||||
std::vector<Glib::ustring> subDirs;
|
||||
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (iter->get_value (dtColumns.dirname));
|
||||
safe_build_subdir_list (dir, subDirs, options.fbShowHidden);
|
||||
safe_build_subdir_list (dir, subDirs, options.fbShowHidden);
|
||||
|
||||
for (int i=0; i<subDirs.size(); i++) {
|
||||
bool found = false;
|
||||
for (Gtk::TreeModel::iterator it=iter->children().begin(); it!=iter->children().end() && !found ; it++)
|
||||
found = (it->get_value (dtColumns.filename)==subDirs[i]);
|
||||
|
||||
if (!found)
|
||||
if (!found) {
|
||||
GThreadLock lock;
|
||||
addDir (iter, subDirs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,9 +359,7 @@ void DirBrowser::file_changed (const Glib::RefPtr<Gio::File>& file, const Glib::
|
||||
if (!file || !safe_file_test (dirName, Glib::FILE_TEST_IS_DIR) || event_type==Gio::FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED)
|
||||
return;
|
||||
|
||||
gdk_threads_enter();
|
||||
updateDir (iter);
|
||||
gdk_threads_leave();
|
||||
}
|
||||
|
||||
void DirBrowser::selectDir (Glib::ustring dir) {
|
||||
|
@@ -24,6 +24,7 @@
|
||||
class DirSelectionListener {
|
||||
|
||||
public:
|
||||
virtual ~DirSelectionListener () {}
|
||||
virtual void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile="") {}
|
||||
};
|
||||
|
||||
|
@@ -597,6 +597,7 @@ struct spparams {
|
||||
|
||||
int setprogressStrUI( void *p )
|
||||
{
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
spparams *s= static_cast<spparams*>(p);
|
||||
|
||||
if( ! s->str.empty() )
|
||||
@@ -662,6 +663,7 @@ void EditorPanel::refreshProcessingState (bool inProcessingP) {
|
||||
s->val = 1.0;
|
||||
|
||||
#ifdef WIN32
|
||||
// Maybe accessing "parent", which is a Gtk object, can justify to get the Gtk lock...
|
||||
if (!firstProcessingDone && static_cast<RTWindow*>(parent)->getIsFullscreen()) { parent->fullscreen(); }
|
||||
#endif
|
||||
firstProcessingDone = true;
|
||||
@@ -1108,19 +1110,11 @@ BatchQueueEntry* EditorPanel::createBatchQueueEntry () {
|
||||
ipc->getParams (&pparams);
|
||||
//rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
||||
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (openThm->getFileName (), openThm->getType()==FT_Raw, pparams);
|
||||
int prevh = options.maxThumbnailHeight;
|
||||
int prevw = prevh;
|
||||
guint8* prev = NULL;//(guint8*) previewHandler->getImagePreview (prevw, prevh);
|
||||
double tmpscale;
|
||||
rtengine::IImage8* img = openThm->processThumbImage (pparams, options.maxThumbnailHeight, tmpscale);
|
||||
if (img) {
|
||||
prevw = img->getWidth ();
|
||||
prevh = img->getHeight ();
|
||||
prev = new guint8 [prevw*prevh*3];
|
||||
memcpy (prev, img->getData (), prevw*prevh*3);
|
||||
img->free();
|
||||
}
|
||||
return new BatchQueueEntry (job, pparams, openThm->getFileName(), prev, prevw, prevh, openThm);
|
||||
int fullW=0, fullH=0;
|
||||
isrc->getImageSource()->getFullSize(fullW, fullH, pparams.coarse.rotate==90 || pparams.coarse.rotate==270 ? TR_R90 : TR_NONE);
|
||||
int prevh = BatchQueue::calcMaxThumbnailHeight();
|
||||
int prevw = int((size_t)fullW * (size_t)prevh / (size_t)fullH);
|
||||
return new BatchQueueEntry (job, pparams, openThm->getFileName(), prevw, prevh, openThm);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "../rtengine/dfmanager.h"
|
||||
#include "../rtengine/ffmanager.h"
|
||||
#include "rtimage.h"
|
||||
#include "guiutils.h"
|
||||
|
||||
extern Options options;
|
||||
|
||||
@@ -106,7 +107,7 @@ FileBrowser::FileBrowser ()
|
||||
/***********************
|
||||
* external programs
|
||||
* *********************/
|
||||
#ifdef WIN32
|
||||
#if PROTECT_VECTORS
|
||||
Gtk::manage(miOpenDefaultViewer=new Gtk::MenuItem (M("FILEBROWSER_OPENDEFAULTVIEWER")));
|
||||
#else
|
||||
miOpenDefaultViewer=NULL;
|
||||
@@ -301,6 +302,12 @@ FileBrowser::~FileBrowser ()
|
||||
|
||||
void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry) {
|
||||
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
trash->set_sensitive (false);
|
||||
untrash->set_sensitive (false);
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
@@ -318,6 +325,7 @@ void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry) {
|
||||
partpasteprof->set_sensitive (clipboard.hasProcParams());
|
||||
copyprof->set_sensitive (selected.size()==1);
|
||||
clearprof->set_sensitive (!selected.empty());
|
||||
}
|
||||
|
||||
// submenu applmenu
|
||||
int p = 0;
|
||||
@@ -336,10 +344,10 @@ void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry) {
|
||||
Gtk::Menu* applpartmenu = Gtk::manage (new Gtk::Menu ());
|
||||
//std::vector<Glib::ustring> profnames = profileStore.getProfileNames (); // this is already created for submenu applmenu above
|
||||
for (size_t i=0; i<profnames.size(); i++) {
|
||||
Gtk::MenuItem* mi = Gtk::manage (new Gtk::MenuItem (profnames[i]));
|
||||
applpartmenu->attach (*mi, 0, 1, p, p+1); p++;
|
||||
mi->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::applyPartialMenuItemActivated), profnames[i]));
|
||||
mi->show ();
|
||||
Gtk::MenuItem* mi = Gtk::manage (new Gtk::MenuItem (profnames[i]));
|
||||
applpartmenu->attach (*mi, 0, 1, p, p+1); p++;
|
||||
mi->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::applyPartialMenuItemActivated), profnames[i]));
|
||||
mi->show ();
|
||||
}
|
||||
applypartprof->set_submenu (*applpartmenu);
|
||||
|
||||
@@ -428,7 +436,7 @@ void FileBrowser::addEntry (FileBrowserEntry* entry) {
|
||||
}
|
||||
|
||||
void FileBrowser::addEntry_ (FileBrowserEntry* entry) {
|
||||
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
entry->selected = false;
|
||||
entry->drawable = false;
|
||||
entry->framed = editedFiles.find (entry->filename)!=editedFiles.end();
|
||||
@@ -439,14 +447,14 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry) {
|
||||
entry->getThumbButtonSet()->setColorLabel (entry->thumbnail->getColorLabel());
|
||||
entry->getThumbButtonSet()->setInTrash (entry->thumbnail->getStage()==1);
|
||||
entry->getThumbButtonSet()->setButtonListener (this);
|
||||
entry->resize (getCurrentThumbSize());
|
||||
entry->resize (getThumbnailHeight());
|
||||
|
||||
// find place in abc order
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
std::vector<ThumbBrowserEntryBase*>::iterator i = fd.begin();
|
||||
while (i!=fd.end() && *entry < *((FileBrowserEntry*)*i))
|
||||
@@ -455,15 +463,15 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry) {
|
||||
fd.insert (i, entry);
|
||||
|
||||
initEntry (entry);
|
||||
}
|
||||
}
|
||||
redraw ();
|
||||
}
|
||||
|
||||
FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) {
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (std::vector<ThumbBrowserEntryBase*>::iterator i=fd.begin(); i!=fd.end(); i++)
|
||||
if ((*i)->filename==fname) {
|
||||
@@ -472,8 +480,8 @@ FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) {
|
||||
fd.erase (i);
|
||||
std::vector<ThumbBrowserEntryBase*>::iterator j = std::find (selected.begin(), selected.end(), entry);
|
||||
|
||||
#ifdef WIN32
|
||||
l.release();
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
|
||||
if (j!=selected.end()) {
|
||||
@@ -486,7 +494,7 @@ FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) {
|
||||
lastClicked = NULL;
|
||||
redraw ();
|
||||
|
||||
return (static_cast<FileBrowserEntry*>(entry));
|
||||
return (static_cast<FileBrowserEntry*>(entry));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -502,22 +510,33 @@ void FileBrowser::close () {
|
||||
fbih->destroyed = false;
|
||||
fbih->pending = 0;
|
||||
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
|
||||
selected.clear ();
|
||||
notifySelectionListener ();
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
selected.clear ();
|
||||
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l); // notifySelectionListener will need read access!
|
||||
#endif
|
||||
|
||||
notifySelectionListener ();
|
||||
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_ACQUIRE(l);
|
||||
#endif
|
||||
|
||||
// The listener merges parameters with old values, so delete afterwards
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
{
|
||||
delete fd[i];
|
||||
delete fd.at(i);
|
||||
}
|
||||
fd.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
lastClicked = NULL;
|
||||
}
|
||||
@@ -537,8 +556,17 @@ void FileBrowser::menuColorlabelActivated (Gtk::MenuItem* m) {
|
||||
void FileBrowser::menuItemActivated (Gtk::MenuItem* m) {
|
||||
|
||||
std::vector<FileBrowserEntry*> mselected;
|
||||
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
|
||||
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
|
||||
}
|
||||
|
||||
|
||||
if (!tbl || (m!=selall && mselected.empty()) )
|
||||
return;
|
||||
@@ -560,8 +588,8 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) {
|
||||
|
||||
// Build vector of all file names
|
||||
std::vector<Glib::ustring> selFileNames;
|
||||
for (int i=0; i<selected.size(); i++) {
|
||||
Glib::ustring fn=selected[i]->thumbnail->getFileName();
|
||||
for (int i=0; i<mselected.size(); i++) {
|
||||
Glib::ustring fn=mselected[i]->thumbnail->getFileName();
|
||||
|
||||
// Maybe batch processed version
|
||||
if (pAct->target==2) fn = Glib::ustring::compose ("%1.%2", BatchQueue::calcAutoFileNameBase(fn), options.saveFormatBatch.format);
|
||||
@@ -576,7 +604,7 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) {
|
||||
|
||||
if (m==open) {
|
||||
std::vector<Thumbnail*> entries;
|
||||
for (size_t i=0; i<mselected.size(); i++)
|
||||
for (size_t i=0; i<mselected.size(); i++)
|
||||
entries.push_back (mselected[i]->thumbnail);
|
||||
tbl->openRequested (entries);
|
||||
}
|
||||
@@ -598,19 +626,19 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) {
|
||||
tbl->renameRequested (mselected);
|
||||
else if (m==selall) {
|
||||
lastClicked = NULL;
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::ReaderLock l(entryRW);
|
||||
#endif
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
selected.clear ();
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
if (checkFilter (fd[i])) {
|
||||
fd[i]->selected = true;
|
||||
selected.push_back (fd[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
queue_draw ();
|
||||
notifySelectionListener ();
|
||||
}
|
||||
@@ -623,86 +651,103 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) {
|
||||
}
|
||||
|
||||
else if (m==autoDF){
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
rtengine::procparams::ProcParams pp=mselected[i]->thumbnail->getProcParams();
|
||||
pp.raw.df_autoselect= true;
|
||||
pp.raw.dark_frame.clear();
|
||||
mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false);
|
||||
}
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->beginBatchPParamsChange(mselected.size());
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
rtengine::procparams::ProcParams pp=mselected[i]->thumbnail->getProcParams();
|
||||
pp.raw.df_autoselect= true;
|
||||
pp.raw.dark_frame.clear();
|
||||
mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false);
|
||||
}
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
|
||||
}else if (m==selectDF){
|
||||
if( !mselected.empty() ){
|
||||
rtengine::procparams::ProcParams pp=mselected[0]->thumbnail->getProcParams();
|
||||
Gtk::FileChooserDialog fc("Dark Frame",Gtk::FILE_CHOOSER_ACTION_OPEN );
|
||||
FileChooserLastFolderPersister persister(&fc, options.lastDarkframeDir);
|
||||
fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
|
||||
fc.add_button( Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY);
|
||||
if(!pp.raw.dark_frame.empty())
|
||||
fc.set_filename( pp.raw.dark_frame );
|
||||
if( fc.run() == Gtk::RESPONSE_APPLY ){
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
rtengine::procparams::ProcParams pp=mselected[i]->thumbnail->getProcParams();
|
||||
pp.raw.dark_frame= fc.get_filename();
|
||||
pp.raw.df_autoselect= false;
|
||||
mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !mselected.empty() ){
|
||||
rtengine::procparams::ProcParams pp=mselected[0]->thumbnail->getProcParams();
|
||||
Gtk::FileChooserDialog fc("Dark Frame",Gtk::FILE_CHOOSER_ACTION_OPEN );
|
||||
FileChooserLastFolderPersister persister(&fc, options.lastDarkframeDir);
|
||||
fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
|
||||
fc.add_button( Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY);
|
||||
if(!pp.raw.dark_frame.empty())
|
||||
fc.set_filename( pp.raw.dark_frame );
|
||||
if( fc.run() == Gtk::RESPONSE_APPLY ) {
|
||||
if (bppcl)
|
||||
bppcl->beginBatchPParamsChange(mselected.size());
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
rtengine::procparams::ProcParams pp=mselected[i]->thumbnail->getProcParams();
|
||||
pp.raw.dark_frame= fc.get_filename();
|
||||
pp.raw.df_autoselect= false;
|
||||
mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false);
|
||||
}
|
||||
if (bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
}
|
||||
}
|
||||
}else if( m==thisIsDF){
|
||||
if( !options.rtSettings.darkFramesPath.empty()) {
|
||||
if (Gio::File::create_for_path(options.rtSettings.darkFramesPath)->query_exists() ){
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
Glib::RefPtr<Gio::File> file = Gio::File::create_for_path ( mselected[i]->filename );
|
||||
if( !file )continue;
|
||||
Glib::ustring destName = options.rtSettings.darkFramesPath+ "/" + file->get_basename();
|
||||
Glib::RefPtr<Gio::File> dest = Gio::File::create_for_path ( destName );
|
||||
file->move( dest );
|
||||
}
|
||||
// Reinit cache
|
||||
rtengine::dfm.init( options.rtSettings.darkFramesPath );
|
||||
}
|
||||
else {
|
||||
// Target directory creation failed, we clear the darkFramesPath setting
|
||||
options.rtSettings.darkFramesPath.clear();
|
||||
Glib::ustring msg_ = Glib::ustring::compose (M("MAIN_MSG_PATHDOESNTEXIST"), options.rtSettings.darkFramesPath)
|
||||
+"\n\n"+M("MAIN_MSG_OPERATIONCANCELLED");
|
||||
Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
msgd.set_title(M("TP_DARKFRAME_LABEL"));
|
||||
msgd.run ();
|
||||
}
|
||||
}
|
||||
else {
|
||||
Glib::ustring msg_ = M("MAIN_MSG_SETPATHFIRST")+"\n\n"+M("MAIN_MSG_OPERATIONCANCELLED");
|
||||
Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
msgd.set_title(M("TP_DARKFRAME_LABEL"));
|
||||
msgd.run ();
|
||||
}
|
||||
if( !options.rtSettings.darkFramesPath.empty()) {
|
||||
if (Gio::File::create_for_path(options.rtSettings.darkFramesPath)->query_exists() ){
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
Glib::RefPtr<Gio::File> file = Gio::File::create_for_path ( mselected[i]->filename );
|
||||
if( !file )continue;
|
||||
Glib::ustring destName = options.rtSettings.darkFramesPath+ "/" + file->get_basename();
|
||||
Glib::RefPtr<Gio::File> dest = Gio::File::create_for_path ( destName );
|
||||
file->move( dest );
|
||||
}
|
||||
// Reinit cache
|
||||
rtengine::dfm.init( options.rtSettings.darkFramesPath );
|
||||
}
|
||||
else {
|
||||
// Target directory creation failed, we clear the darkFramesPath setting
|
||||
options.rtSettings.darkFramesPath.clear();
|
||||
Glib::ustring msg_ = Glib::ustring::compose (M("MAIN_MSG_PATHDOESNTEXIST"), options.rtSettings.darkFramesPath)
|
||||
+"\n\n"+M("MAIN_MSG_OPERATIONCANCELLED");
|
||||
Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
msgd.set_title(M("TP_DARKFRAME_LABEL"));
|
||||
msgd.run ();
|
||||
}
|
||||
}
|
||||
else {
|
||||
Glib::ustring msg_ = M("MAIN_MSG_SETPATHFIRST")+"\n\n"+M("MAIN_MSG_OPERATIONCANCELLED");
|
||||
Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
msgd.set_title(M("TP_DARKFRAME_LABEL"));
|
||||
msgd.run ();
|
||||
}
|
||||
}
|
||||
else if (m==autoFF){
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
rtengine::procparams::ProcParams pp=mselected[i]->thumbnail->getProcParams();
|
||||
pp.raw.ff_AutoSelect= true;
|
||||
pp.raw.ff_file.clear();
|
||||
mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false);
|
||||
}
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->beginBatchPParamsChange(mselected.size());
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
rtengine::procparams::ProcParams pp=mselected[i]->thumbnail->getProcParams();
|
||||
pp.raw.ff_AutoSelect= true;
|
||||
pp.raw.ff_file.clear();
|
||||
mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false);
|
||||
}
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
}
|
||||
else if (m==selectFF){
|
||||
if( !mselected.empty() ){
|
||||
rtengine::procparams::ProcParams pp=mselected[0]->thumbnail->getProcParams();
|
||||
Gtk::FileChooserDialog fc("Flat Field",Gtk::FILE_CHOOSER_ACTION_OPEN );
|
||||
FileChooserLastFolderPersister persister(&fc, options.lastFlatfieldDir);
|
||||
fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
|
||||
fc.add_button( Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY);
|
||||
if(!pp.raw.ff_file.empty())
|
||||
fc.set_filename( pp.raw.ff_file );
|
||||
if( fc.run() == Gtk::RESPONSE_APPLY ){
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
rtengine::procparams::ProcParams pp=mselected[i]->thumbnail->getProcParams();
|
||||
pp.raw.ff_file= fc.get_filename();
|
||||
pp.raw.ff_AutoSelect= false;
|
||||
mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !mselected.empty() ){
|
||||
rtengine::procparams::ProcParams pp=mselected[0]->thumbnail->getProcParams();
|
||||
Gtk::FileChooserDialog fc("Flat Field",Gtk::FILE_CHOOSER_ACTION_OPEN );
|
||||
FileChooserLastFolderPersister persister(&fc, options.lastFlatfieldDir);
|
||||
fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
|
||||
fc.add_button( Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY);
|
||||
if(!pp.raw.ff_file.empty())
|
||||
fc.set_filename( pp.raw.ff_file );
|
||||
if( fc.run() == Gtk::RESPONSE_APPLY ) {
|
||||
if (bppcl)
|
||||
bppcl->beginBatchPParamsChange(mselected.size());
|
||||
for (size_t i=0; i<mselected.size(); i++){
|
||||
rtengine::procparams::ProcParams pp=mselected[i]->thumbnail->getProcParams();
|
||||
pp.raw.ff_file= fc.get_filename();
|
||||
pp.raw.ff_AutoSelect= false;
|
||||
mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false);
|
||||
}
|
||||
if (bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( m==thisIsFF){
|
||||
if( !options.rtSettings.flatFieldsPath.empty()) {
|
||||
@@ -745,13 +790,17 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) {
|
||||
mselected[i]->thumbnail->clearProcParams (FILEBROWSER);
|
||||
queue_draw ();
|
||||
} else if (m==execcustprof) {
|
||||
for (size_t i=0; i<mselected.size(); i++) {
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->beginBatchPParamsChange(mselected.size());
|
||||
for (size_t i=0; i<mselected.size(); i++) {
|
||||
mselected[i]->thumbnail->createProcParamsForUpdate (false, true);
|
||||
|
||||
// Empty run to update the thumb
|
||||
rtengine::procparams::ProcParams params = mselected[i]->thumbnail->getProcParams ();
|
||||
mselected[i]->thumbnail->setProcParams (params, NULL, FILEBROWSER);
|
||||
}
|
||||
}
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
} else if (m==clearFromCache) {
|
||||
for (size_t i=0; i<mselected.size(); i++)
|
||||
tbl->clearFromCacheRequested (mselected, false);
|
||||
@@ -767,6 +816,10 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) {
|
||||
}
|
||||
|
||||
void FileBrowser::copyProfile () {
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (selected.size()==1)
|
||||
clipboard.setProcParams ((static_cast<FileBrowserEntry*>(selected[0]))->thumbnail->getProcParams());
|
||||
@@ -776,12 +829,21 @@ void FileBrowser::pasteProfile () {
|
||||
|
||||
if (clipboard.hasProcParams()) {
|
||||
std::vector<FileBrowserEntry*> mselected;
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (unsigned int i=0; i<selected.size(); i++)
|
||||
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
|
||||
}
|
||||
|
||||
if (!tbl || mselected.empty())
|
||||
return;
|
||||
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->beginBatchPParamsChange(mselected.size());
|
||||
for (unsigned int i=0; i<mselected.size(); i++) {
|
||||
// copying read only clipboard PartialProfile to a temporary one
|
||||
rtengine::procparams::PartialProfile cbPartProf = clipboard.getPartialProfile();
|
||||
@@ -791,6 +853,8 @@ void FileBrowser::pasteProfile () {
|
||||
mselected[i]->thumbnail->setProcParams (*pastedPartProf.pparams, pastedPartProf.pedited, FILEBROWSER);
|
||||
pastedPartProf.deleteInstance();
|
||||
}
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
@@ -801,8 +865,15 @@ void FileBrowser::partPasteProfile () {
|
||||
if (clipboard.hasProcParams()) {
|
||||
|
||||
std::vector<FileBrowserEntry*> mselected;
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (unsigned int i=0; i<selected.size(); i++)
|
||||
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
|
||||
}
|
||||
|
||||
if (!tbl || mselected.empty())
|
||||
return;
|
||||
@@ -810,6 +881,8 @@ void FileBrowser::partPasteProfile () {
|
||||
int i = partialPasteDlg.run ();
|
||||
if (i == Gtk::RESPONSE_OK) {
|
||||
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->beginBatchPParamsChange(mselected.size());
|
||||
for (unsigned int i=0; i<mselected.size(); i++) {
|
||||
// copying read only clipboard PartialProfile to a temporary one, initialized to the thumb's ProcParams
|
||||
mselected[i]->thumbnail->createProcParamsForUpdate(false,false); // this can execute customprofilebuilder to generate param file
|
||||
@@ -823,6 +896,8 @@ void FileBrowser::partPasteProfile () {
|
||||
mselected[i]->thumbnail->setProcParams (*pastedPartProf.pparams, pastedPartProf.pedited, FILEBROWSER);
|
||||
pastedPartProf.deleteInstance();
|
||||
}
|
||||
if (!mselected.empty() && bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
@@ -832,9 +907,17 @@ void FileBrowser::partPasteProfile () {
|
||||
|
||||
void FileBrowser::openDefaultViewer (int destination) {
|
||||
bool success=true;
|
||||
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (selected.size()==1)
|
||||
success=(static_cast<FileBrowserEntry*>(selected[0]))->thumbnail->openDefaultViewer(destination);
|
||||
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Gtk::MessageDialog msgd (M("MAIN_MSG_IMAGEUNPROCESSED"), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
msgd.run ();
|
||||
@@ -956,18 +1039,47 @@ bool FileBrowser::keyPressed (GdkEventKey* event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileBrowser::saveThumbnailHeight (int height) {
|
||||
if (!options.sameThumbSize && inTabMode)
|
||||
options.thumbSizeTab = height;
|
||||
else
|
||||
options.thumbSize = height;
|
||||
}
|
||||
|
||||
int FileBrowser::getThumbnailHeight () {
|
||||
// The user could have manually forced the option to a too big value
|
||||
if (!options.sameThumbSize && inTabMode)
|
||||
return std::max(std::min(options.thumbSizeTab, 200), 10);
|
||||
else
|
||||
return std::max(std::min(options.thumbSize, 200), 10);
|
||||
}
|
||||
|
||||
void FileBrowser::applyMenuItemActivated (Glib::ustring ppname) {
|
||||
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
const rtengine::procparams::PartialProfile* partProfile = profileStore.getProfile (ppname);
|
||||
if (partProfile->pparams && !selected.empty()) {
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
if (bppcl)
|
||||
bppcl->beginBatchPParamsChange(selected.size());
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
(static_cast<FileBrowserEntry*>(selected[i]))->thumbnail->setProcParams (*partProfile->pparams, partProfile->pedited, FILEBROWSER);
|
||||
if (bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
queue_draw ();
|
||||
}
|
||||
}
|
||||
|
||||
void FileBrowser::applyPartialMenuItemActivated (Glib::ustring ppname) {
|
||||
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (!tbl || selected.empty())
|
||||
return;
|
||||
|
||||
@@ -976,6 +1088,8 @@ void FileBrowser::applyPartialMenuItemActivated (Glib::ustring ppname) {
|
||||
if (srcProfiles->pparams) {
|
||||
if (partialPasteDlg.run()==Gtk::RESPONSE_OK) {
|
||||
|
||||
if (bppcl)
|
||||
bppcl->beginBatchPParamsChange(selected.size());
|
||||
for (size_t i=0; i<selected.size(); i++) {
|
||||
selected[i]->thumbnail->createProcParamsForUpdate(false, false); // this can execute customprofilebuilder to generate param file
|
||||
|
||||
@@ -986,6 +1100,8 @@ void FileBrowser::applyPartialMenuItemActivated (Glib::ustring ppname) {
|
||||
(static_cast<FileBrowserEntry*>(selected[i]))->thumbnail->setProcParams (*dstProfile.pparams, dstProfile.pedited, FILEBROWSER);
|
||||
dstProfile.deleteInstance();
|
||||
}
|
||||
if (bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
queue_draw ();
|
||||
}
|
||||
partialPasteDlg.hide ();
|
||||
@@ -999,16 +1115,16 @@ void FileBrowser::applyFilter (const BrowserFilter& filter) {
|
||||
// remove items not complying the filter from the selection
|
||||
bool selchanged = false;
|
||||
numFiltered=0;
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::ReaderLock l(entryRW); // Don't make this a writer lock!
|
||||
#endif
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW); // Don't make this a writer lock! HOMBRE: Why? 'selected' is modified here
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<fd.size(); i++) {
|
||||
if (checkFilter (fd[i]))
|
||||
numFiltered++;
|
||||
else if (fd[i]->selected ) {
|
||||
for (size_t i=0; i<fd.size(); i++) {
|
||||
if (checkFilter (fd[i]))
|
||||
numFiltered++;
|
||||
else if (fd[i]->selected ) {
|
||||
fd[i]->selected = false;
|
||||
std::vector<ThumbBrowserEntryBase*>::iterator j = std::find (selected.begin(), selected.end(), fd[i]);
|
||||
selected.erase (j);
|
||||
@@ -1017,7 +1133,7 @@ void FileBrowser::applyFilter (const BrowserFilter& filter) {
|
||||
selchanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selchanged)
|
||||
notifySelectionListener ();
|
||||
@@ -1138,42 +1254,59 @@ void FileBrowser::fromTrashRequested (std::vector<FileBrowserEntry*> tbe) {
|
||||
|
||||
void FileBrowser::rankingRequested (std::vector<FileBrowserEntry*> tbe, int rank) {
|
||||
|
||||
for (size_t i=0; i<tbe.size(); i++) {
|
||||
// try to load the last saved parameters from the cache or from the paramfile file
|
||||
tbe[i]->thumbnail->createProcParamsForUpdate(false, false); // this can execute customprofilebuilder to generate param file
|
||||
if (!tbe.empty() && bppcl)
|
||||
bppcl->beginBatchPParamsChange(tbe.size());
|
||||
|
||||
// notify listeners TODO: should do this ONLY when params changed by customprofilebuilder?
|
||||
tbe[i]->thumbnail->notifylisterners_procParamsChanged(FILEBROWSER);
|
||||
for (size_t i=0; i<tbe.size(); i++) {
|
||||
|
||||
// try to load the last saved parameters from the cache or from the paramfile file
|
||||
tbe[i]->thumbnail->createProcParamsForUpdate(false, false); // this can execute customprofilebuilder to generate param file
|
||||
|
||||
// notify listeners TODO: should do this ONLY when params changed by customprofilebuilder?
|
||||
tbe[i]->thumbnail->notifylisterners_procParamsChanged(FILEBROWSER);
|
||||
|
||||
tbe[i]->thumbnail->setRank (rank);
|
||||
tbe[i]->thumbnail->updateCache (); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file
|
||||
//TODO? - should update pparams instead?
|
||||
|
||||
if (tbe[i]->getThumbButtonSet())
|
||||
tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank());
|
||||
tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank());
|
||||
}
|
||||
applyFilter (filter);
|
||||
|
||||
if (!tbe.empty() && bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
}
|
||||
|
||||
void FileBrowser::colorlabelRequested (std::vector<FileBrowserEntry*> tbe, int colorlabel) {
|
||||
|
||||
for (size_t i=0; i<tbe.size(); i++) {
|
||||
// try to load the last saved parameters from the cache or from the paramfile file
|
||||
tbe[i]->thumbnail->createProcParamsForUpdate(false, false); // this can execute customprofilebuilder to generate param file
|
||||
if (!tbe.empty() && bppcl)
|
||||
bppcl->beginBatchPParamsChange(tbe.size());
|
||||
|
||||
// notify listeners TODO: should do this ONLY when params changed by customprofilebuilder?
|
||||
tbe[i]->thumbnail->notifylisterners_procParamsChanged(FILEBROWSER);
|
||||
for (size_t i=0; i<tbe.size(); i++) {
|
||||
// try to load the last saved parameters from the cache or from the paramfile file
|
||||
tbe[i]->thumbnail->createProcParamsForUpdate(false, false); // this can execute customprofilebuilder to generate param file
|
||||
|
||||
// notify listeners TODO: should do this ONLY when params changed by customprofilebuilder?
|
||||
tbe[i]->thumbnail->notifylisterners_procParamsChanged(FILEBROWSER);
|
||||
|
||||
tbe[i]->thumbnail->setColorLabel (colorlabel);
|
||||
tbe[i]->thumbnail->updateCache(); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file
|
||||
//TODO? - should update pparams instead?
|
||||
if (tbe[i]->getThumbButtonSet())
|
||||
tbe[i]->getThumbButtonSet()->setColorLabel (tbe[i]->thumbnail->getColorLabel());
|
||||
tbe[i]->getThumbButtonSet()->setColorLabel (tbe[i]->thumbnail->getColorLabel());
|
||||
}
|
||||
applyFilter (filter);
|
||||
|
||||
if (!tbe.empty() && bppcl)
|
||||
bppcl->endBatchPParamsChange();
|
||||
}
|
||||
|
||||
void FileBrowser::requestRanking(int rank){
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
std::vector<FileBrowserEntry*> mselected;
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
|
||||
@@ -1182,6 +1315,10 @@ void FileBrowser::requestRanking(int rank){
|
||||
}
|
||||
|
||||
void FileBrowser::requestColorLabel(int colorlabel){
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
std::vector<FileBrowserEntry*> mselected;
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
|
||||
@@ -1219,8 +1356,8 @@ void FileBrowser::buttonPressed (LWButton* button, int actionCode, void* actionD
|
||||
|
||||
void FileBrowser::openNextImage () {
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::ReaderLock l(entryRW);
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (!fd.empty() && selected.size()>0 && !options.tabbedUI) {
|
||||
@@ -1240,8 +1377,18 @@ void FileBrowser::openNextImage () {
|
||||
fd[k]->selected = true;
|
||||
selected.push_back (fd[k]);
|
||||
//queue_draw ();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
|
||||
// this will require a read access
|
||||
notifySelectionListener ();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_ACQUIRE(l);
|
||||
#endif
|
||||
|
||||
// scroll to the selected position
|
||||
double h1, v1;
|
||||
getScrollPosition(h1,v1);
|
||||
@@ -1249,15 +1396,22 @@ void FileBrowser::openNextImage () {
|
||||
double h2=selected[0]->getStartX();
|
||||
double v2=selected[0]->getStartY();
|
||||
|
||||
Thumbnail* thumb = (static_cast<FileBrowserEntry*>(fd[k]))->thumbnail;
|
||||
int minWidth = get_width()-fd[k]->getMinimalWidth();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
|
||||
// scroll only when selected[0] is outside of the displayed bounds
|
||||
if (h2+fd[k]->getMinimalWidth()-h1 > get_width())
|
||||
setScrollPosition(h2-(get_width()-fd[k]->getMinimalWidth()),v2);
|
||||
if (h2+minWidth-h1 > get_width())
|
||||
setScrollPosition(h2-minWidth,v2);
|
||||
if (h1>h2)
|
||||
setScrollPosition(h2,v2);
|
||||
|
||||
// open the selected image
|
||||
std::vector<Thumbnail*> entries;
|
||||
entries.push_back ((static_cast<FileBrowserEntry*>(fd[k]))->thumbnail);
|
||||
entries.push_back (thumb);
|
||||
tbl->openRequested (entries);
|
||||
return;
|
||||
}
|
||||
@@ -1270,8 +1424,8 @@ void FileBrowser::openNextImage () {
|
||||
|
||||
void FileBrowser::openPrevImage () {
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::ReaderLock l(entryRW);
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (!fd.empty() && selected.size()>0 && !options.tabbedUI) {
|
||||
@@ -1291,8 +1445,18 @@ void FileBrowser::openPrevImage () {
|
||||
fd[k]->selected = true;
|
||||
selected.push_back (fd[k]);
|
||||
//queue_draw ();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
|
||||
// this will require a read access
|
||||
notifySelectionListener ();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_ACQUIRE(l);
|
||||
#endif
|
||||
|
||||
// scroll to the selected position
|
||||
double h1, v1;
|
||||
getScrollPosition(h1,v1);
|
||||
@@ -1300,15 +1464,22 @@ void FileBrowser::openPrevImage () {
|
||||
double h2=selected[0]->getStartX();
|
||||
double v2=selected[0]->getStartY();
|
||||
|
||||
Thumbnail* thumb = (static_cast<FileBrowserEntry*>(fd[k]))->thumbnail;
|
||||
int minWidth = get_width()-fd[k]->getMinimalWidth();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
|
||||
// scroll only when selected[0] is outside of the displayed bounds
|
||||
if (h2+fd[k]->getMinimalWidth()-h1 > get_width())
|
||||
setScrollPosition(h2-(get_width()-fd[k]->getMinimalWidth()),v2);
|
||||
if (h2+minWidth-h1 > get_width())
|
||||
setScrollPosition(h2-minWidth,v2);
|
||||
if (h1>h2)
|
||||
setScrollPosition(h2,v2);
|
||||
|
||||
// open the selected image
|
||||
std::vector<Thumbnail*> entries;
|
||||
entries.push_back ((static_cast<FileBrowserEntry*>(fd[k]))->thumbnail);
|
||||
entries.push_back (thumb);
|
||||
tbl->openRequested (entries);
|
||||
return;
|
||||
}
|
||||
@@ -1324,6 +1495,11 @@ void FileBrowser::selectImage (Glib::ustring fname) {
|
||||
|
||||
// need to clear the filter in filecatalog
|
||||
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (!fd.empty() && !options.tabbedUI) {
|
||||
for (size_t i=0; i<fd.size(); i++){
|
||||
if (fname==fd[i]->filename && !fd[i]->filtered) {
|
||||
@@ -1338,11 +1514,26 @@ void FileBrowser::selectImage (Glib::ustring fname) {
|
||||
fd[i]->selected = true;
|
||||
selected.push_back (fd[i]);
|
||||
queue_draw ();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
|
||||
// this will require a read access
|
||||
notifySelectionListener ();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_ACQUIRE(l);
|
||||
#endif
|
||||
|
||||
// scroll to the selected position
|
||||
double h=selected[0]->getStartX();
|
||||
double v=selected[0]->getStartY();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
|
||||
setScrollPosition(h,v);
|
||||
|
||||
return;
|
||||
@@ -1373,6 +1564,7 @@ void FileBrowser::_thumbRearrangementNeeded () {
|
||||
}
|
||||
|
||||
void FileBrowser::thumbRearrangementNeeded () {
|
||||
// refreshThumbImagesUI will handle thread safety itself
|
||||
g_idle_add (refreshThumbImagesUI, this);
|
||||
}
|
||||
|
||||
@@ -1384,15 +1576,20 @@ void FileBrowser::selectionChanged () {
|
||||
void FileBrowser::notifySelectionListener () {
|
||||
|
||||
if (tbl) {
|
||||
// TODO: Check for Linux
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
std::vector<Thumbnail*> thm;
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
thm.push_back ((static_cast<FileBrowserEntry*>(selected[i]))->thumbnail);
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
thm.push_back ((static_cast<FileBrowserEntry*>(selected[i]))->thumbnail);
|
||||
tbl->selectionChanged (thm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileBrowser::redrawNeeded (LWButton* button) {
|
||||
|
||||
GThreadLock lock;
|
||||
queue_draw ();
|
||||
}
|
||||
FileBrowser::type_trash_changed FileBrowser::trash_changed () {
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "exiffiltersettings.h"
|
||||
#include "filebrowserentry.h"
|
||||
#include "browserfilter.h"
|
||||
#include "pparamschangelistener.h"
|
||||
#include "partialpastedlg.h"
|
||||
#include "exportpanel.h"
|
||||
#include "extprog.h"
|
||||
@@ -34,6 +35,7 @@ class FileBrowserEntry;
|
||||
class FileBrowserListener {
|
||||
|
||||
public:
|
||||
virtual ~FileBrowserListener () {}
|
||||
virtual void openRequested (std::vector<Thumbnail*> tbe) {}
|
||||
virtual void developRequested (std::vector<FileBrowserEntry*> tbe, bool fastmode) {}
|
||||
virtual void renameRequested (std::vector<FileBrowserEntry*> tbe) {}
|
||||
@@ -112,6 +114,7 @@ class FileBrowser : public ThumbBrowserBase,
|
||||
|
||||
Glib::RefPtr<Gtk::AccelGroup> pmaccelgroup;
|
||||
|
||||
BatchPParamsChangeListener* bppcl;
|
||||
FileBrowserListener* tbl;
|
||||
BrowserFilter filter;
|
||||
int numFiltered;
|
||||
@@ -140,6 +143,7 @@ class FileBrowser : public ThumbBrowserBase,
|
||||
FileBrowserEntry* delEntry (const Glib::ustring& fname); // return the entry if found here return NULL otherwise
|
||||
void close ();
|
||||
|
||||
void setBatchPParamsChangeListener (BatchPParamsChangeListener* l) { bppcl = l; }
|
||||
void setFileBrowserListener (FileBrowserListener* l) { tbl = l; }
|
||||
|
||||
void menuItemActivated (Gtk::MenuItem* m);
|
||||
@@ -156,6 +160,9 @@ class FileBrowser : public ThumbBrowserBase,
|
||||
void doubleClicked (ThumbBrowserEntryBase* entry);
|
||||
bool keyPressed (GdkEventKey* event);
|
||||
|
||||
void saveThumbnailHeight (int height);
|
||||
int getThumbnailHeight ();
|
||||
|
||||
void openNextImage ();
|
||||
void openPrevImage ();
|
||||
void copyProfile ();
|
||||
|
@@ -203,11 +203,14 @@ void FileBrowserEntry::updateImage (rtengine::IImage8* img, double scale, rtengi
|
||||
param->img = img;
|
||||
param->scale = scale;
|
||||
param->cropParams = cropParams;
|
||||
g_idle_add (updateImageUI, param);
|
||||
g_idle_add_full (G_PRIORITY_LOW, updateImageUI, param, NULL);
|
||||
}
|
||||
|
||||
void FileBrowserEntry::_updateImage (rtengine::IImage8* img, double s, rtengine::procparams::CropParams cropParams) {
|
||||
Glib::RWLock::WriterLock l(lockRW);
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, lockRW);
|
||||
#endif
|
||||
|
||||
redrawRequests--;
|
||||
scale = s;
|
||||
@@ -219,6 +222,8 @@ void FileBrowserEntry::_updateImage (rtengine::IImage8* img, double s, rtengine:
|
||||
if (preh == img->getHeight ()) {
|
||||
prew = img->getWidth ();
|
||||
|
||||
GThreadLock lock;
|
||||
|
||||
// Check if image has been rotated since last time
|
||||
rotated = preview!=NULL && newLandscape!=landscape;
|
||||
|
||||
|
@@ -38,8 +38,6 @@ using namespace std;
|
||||
|
||||
#define CHECKTIME 2000
|
||||
|
||||
extern Glib::ustring argv0;
|
||||
|
||||
FileCatalog::FileCatalog (CoarsePanel* cp, ToolBar* tb, FilePanel* filepanel) :
|
||||
filepanel(filepanel),
|
||||
selectedDirectoryId(1),
|
||||
@@ -462,9 +460,12 @@ void FileCatalog::closeDir () {
|
||||
// remove entries
|
||||
selectedDirectory = "";
|
||||
fileBrowser->close ();
|
||||
fileNameList.clear ();
|
||||
|
||||
fileNameList.clear ();
|
||||
|
||||
{
|
||||
Glib::Mutex::Lock lock(filterMutex);
|
||||
dirEFS.clear ();
|
||||
}
|
||||
hasValidCurrentEFS = false;
|
||||
redrawAll ();
|
||||
}
|
||||
@@ -537,13 +538,15 @@ void FileCatalog::_refreshProgressBar () {
|
||||
// Also mention that this progress bar only measures the FIRST pass (quick thumbnails)
|
||||
// The second, usually longer pass is done multithreaded down in the single entries and is NOT measured by this
|
||||
if (!inTabMode) {
|
||||
Gtk::Notebook *nb =(Gtk::Notebook *)(filepanel->get_parent());
|
||||
Gtk::Box* hbb=NULL;
|
||||
Gtk::Label *label=NULL;
|
||||
if( options.mainNBVertical )
|
||||
hbb = Gtk::manage (new Gtk::VBox ());
|
||||
else
|
||||
hbb = Gtk::manage (new Gtk::HBox ());
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
|
||||
Gtk::Notebook *nb =(Gtk::Notebook *)(filepanel->get_parent());
|
||||
Gtk::Box* hbb=NULL;
|
||||
Gtk::Label *label=NULL;
|
||||
if( options.mainNBVertical )
|
||||
hbb = Gtk::manage (new Gtk::VBox ());
|
||||
else
|
||||
hbb = Gtk::manage (new Gtk::HBox ());
|
||||
if (!previewsToLoad ) {
|
||||
hbb->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU)));
|
||||
int filteredCount=fileBrowser->getNumFiltered();
|
||||
@@ -573,17 +576,9 @@ int refreshProgressBarUI (void* data) {
|
||||
}
|
||||
|
||||
void FileCatalog::previewReady (int dir_id, FileBrowserEntry* fdn) {
|
||||
GThreadLock lock;
|
||||
previewReadyUI (dir_id,fdn);
|
||||
}
|
||||
|
||||
// Called WITHIN gtk thread
|
||||
void FileCatalog::previewReadyUI (int dir_id, FileBrowserEntry* fdn) {
|
||||
|
||||
if ( dir_id != selectedDirectoryId )
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ( dir_id != selectedDirectoryId )
|
||||
return;
|
||||
|
||||
// put it into the "full directory" browser
|
||||
fdn->setImageAreaToolListener (iatlistener);
|
||||
@@ -591,6 +586,9 @@ void FileCatalog::previewReadyUI (int dir_id, FileBrowserEntry* fdn) {
|
||||
|
||||
// update exif filter settings (minimal & maximal values of exif tags, cameras, lenses, etc...)
|
||||
const CacheImageData* cfs = fdn->thumbnail->getCacheImageData();
|
||||
|
||||
{
|
||||
Glib::Mutex::Lock lock(filterMutex);
|
||||
if (cfs->exifValid) {
|
||||
if (cfs->fnumber < dirEFS.fnumberFrom)
|
||||
dirEFS.fnumberFrom = cfs->fnumber;
|
||||
@@ -613,13 +611,14 @@ void FileCatalog::previewReadyUI (int dir_id, FileBrowserEntry* fdn) {
|
||||
dirEFS.cameras.insert (cfs->camera);
|
||||
dirEFS.lenses.insert (cfs->lens);
|
||||
dirEFS.expcomp.insert (cfs->expcomp);
|
||||
}
|
||||
|
||||
previewsLoaded++;
|
||||
|
||||
g_idle_add (refreshProgressBarUI, this);
|
||||
}
|
||||
|
||||
int prevfinished (void* data) {
|
||||
GThreadLock lock;
|
||||
(static_cast<FileCatalog*>(data))->previewsFinishedUI ();
|
||||
return 0;
|
||||
}
|
||||
@@ -627,26 +626,30 @@ int prevfinished (void* data) {
|
||||
// Called within GTK UI thread
|
||||
void FileCatalog::previewsFinishedUI () {
|
||||
|
||||
redrawAll ();
|
||||
previewsToLoad = 0;
|
||||
{
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
redrawAll ();
|
||||
previewsToLoad = 0;
|
||||
|
||||
if (filterPanel) {
|
||||
filterPanel->set_sensitive (true);
|
||||
if ( !hasValidCurrentEFS ){
|
||||
currentEFS = dirEFS;
|
||||
filterPanel->setFilter ( dirEFS,true );
|
||||
}else {
|
||||
filterPanel->setFilter ( currentEFS,false );
|
||||
}
|
||||
}
|
||||
|
||||
if (exportPanel)
|
||||
exportPanel->set_sensitive (true);
|
||||
if (filterPanel) {
|
||||
filterPanel->set_sensitive (true);
|
||||
Glib::Mutex::Lock lock(filterMutex);
|
||||
if ( !hasValidCurrentEFS ){
|
||||
currentEFS = dirEFS;
|
||||
filterPanel->setFilter ( dirEFS,true );
|
||||
}else {
|
||||
filterPanel->setFilter ( currentEFS,false );
|
||||
}
|
||||
}
|
||||
|
||||
// restart anything that might have been loaded low quality
|
||||
fileBrowser->refreshQuickThumbImages();
|
||||
fileBrowser->applyFilter (getFilter()); // refresh total image count
|
||||
_refreshProgressBar();
|
||||
if (exportPanel)
|
||||
exportPanel->set_sensitive (true);
|
||||
|
||||
// restart anything that might have been loaded low quality
|
||||
fileBrowser->refreshQuickThumbImages();
|
||||
fileBrowser->applyFilter (getFilter()); // refresh total image count
|
||||
_refreshProgressBar();
|
||||
}
|
||||
filepanel->loadingThumbs(M("PROGRESSBAR_READY"),0);
|
||||
|
||||
if (!imageToSelect_fname.empty()){
|
||||
@@ -668,8 +671,10 @@ void FileCatalog::previewsFinished (int dir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasValidCurrentEFS)
|
||||
if (!hasValidCurrentEFS) {
|
||||
Glib::Mutex::Lock lock(filterMutex);
|
||||
currentEFS = dirEFS;
|
||||
}
|
||||
|
||||
g_idle_add (prevfinished, this);
|
||||
}
|
||||
@@ -689,9 +694,9 @@ void FileCatalog::refreshThumbImages () {
|
||||
void FileCatalog::refreshHeight () {
|
||||
int newHeight=fileBrowser->getEffectiveHeight() + buttonBar->get_height();
|
||||
if (!options.FileBrowserToolbarSingleRow) {
|
||||
newHeight += hbToolBar1->get_height();
|
||||
newHeight += hbToolBar1->get_height();
|
||||
}
|
||||
set_size_request(0, newHeight);
|
||||
set_size_request(0, newHeight+2); // HOMBRE: yeah, +2, there's always 2 pixels missing... sorry for this dirty hack O:)
|
||||
}
|
||||
|
||||
void FileCatalog::_openImage (std::vector<Thumbnail*> tmb) {
|
||||
@@ -879,11 +884,14 @@ void FileCatalog::developRequested (std::vector<FileBrowserEntry*> tbe, bool fas
|
||||
if (listener) {
|
||||
std::vector<BatchQueueEntry*> entries;
|
||||
|
||||
#pragma omp parallel for ordered
|
||||
// TODO: (HOMBRE) should we still use parallelization here, now that thumbnails are processed asynchronously...?
|
||||
//#pragma omp parallel for ordered
|
||||
for (size_t i=0; i<tbe.size(); i++) {
|
||||
rtengine::procparams::ProcParams params = tbe[i]->thumbnail->getProcParams();
|
||||
FileBrowserEntry* fbe = tbe[i];
|
||||
Thumbnail* th = fbe->thumbnail;
|
||||
rtengine::procparams::ProcParams params = th->getProcParams();
|
||||
|
||||
// if fast mode is selected, override (disable) prams
|
||||
// if fast mode is selected, override (disable) params
|
||||
// controlling time and resource consuming tasks
|
||||
// and also those which effect is not pronounced after reducing the image size
|
||||
// TODO!!! could expose selections below via preferences
|
||||
@@ -921,30 +929,19 @@ void FileCatalog::developRequested (std::vector<FileBrowserEntry*> tbe, bool fas
|
||||
params.resize.height = options.fastexport_resize_height ;
|
||||
}
|
||||
|
||||
rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (tbe[i]->filename, tbe[i]->thumbnail->getType()==FT_Raw, params);
|
||||
double tmpscale;
|
||||
rtengine::IImage8* img = tbe[i]->thumbnail->processThumbImage (params, BatchQueue::calcMaxThumbnailHeight(), tmpscale);
|
||||
rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType()==FT_Raw, params);
|
||||
|
||||
int pw, ph;
|
||||
guint8* prev=NULL;
|
||||
|
||||
if (img) {
|
||||
pw = img->getWidth ();
|
||||
ph = img->getHeight ();
|
||||
prev = new guint8 [pw*ph*3];
|
||||
memcpy (prev, img->getData (), pw*ph*3);
|
||||
img->free();
|
||||
|
||||
} else {
|
||||
tbe[i]->thumbnail->getThumbnailSize (pw, ph);
|
||||
}
|
||||
int pw;
|
||||
int ph = BatchQueue::calcMaxThumbnailHeight();
|
||||
th->getThumbnailSize (pw, ph);
|
||||
|
||||
// processThumbImage is the processing intensive part, but adding to queue must be ordered
|
||||
#pragma omp ordered
|
||||
{
|
||||
entries.push_back(new BatchQueueEntry (pjob, params, tbe[i]->filename, prev, pw, ph, tbe[i]->thumbnail));
|
||||
}
|
||||
}
|
||||
//#pragma omp ordered
|
||||
//{
|
||||
BatchQueueEntry* bqh = new BatchQueueEntry (pjob, params, fbe->filename, pw, ph, th);
|
||||
entries.push_back(bqh);
|
||||
//}
|
||||
}
|
||||
|
||||
listener->addBatchQueueJobs( entries );
|
||||
}
|
||||
@@ -1324,8 +1321,10 @@ BrowserFilter FileCatalog::getFilter () {
|
||||
if (!filterPanel)
|
||||
filter.exifFilterEnabled = false;
|
||||
else {
|
||||
if (!hasValidCurrentEFS)
|
||||
Glib::Mutex::Lock lock(filterMutex);
|
||||
if (!hasValidCurrentEFS) {
|
||||
filter.exifFilter = dirEFS;
|
||||
}
|
||||
else
|
||||
filter.exifFilter = currentEFS;
|
||||
filter.exifFilterEnabled = filterPanel->isEnabled ();
|
||||
@@ -1408,15 +1407,14 @@ void FileCatalog::winDirChanged () {
|
||||
|
||||
void FileCatalog::on_dir_changed (const Glib::RefPtr<Gio::File>& file, const Glib::RefPtr<Gio::File>& other_file, Gio::FileMonitorEvent event_type, bool internal) {
|
||||
|
||||
if (options.has_retained_extention(file->get_parse_name())) {
|
||||
if (!internal)
|
||||
gdk_threads_enter();
|
||||
|
||||
if (event_type == Gio::FILE_MONITOR_EVENT_CREATED || event_type == Gio::FILE_MONITOR_EVENT_DELETED || event_type == Gio::FILE_MONITOR_EVENT_CHANGED)
|
||||
reparseDirectory ();
|
||||
|
||||
if (!internal)
|
||||
gdk_threads_leave();
|
||||
if (options.has_retained_extention(file->get_parse_name())
|
||||
&& (event_type == Gio::FILE_MONITOR_EVENT_CREATED || event_type == Gio::FILE_MONITOR_EVENT_DELETED || event_type == Gio::FILE_MONITOR_EVENT_CHANGED)) {
|
||||
if (!internal) {
|
||||
GThreadLock lock;
|
||||
reparseDirectory ();
|
||||
}
|
||||
else
|
||||
reparseDirectory ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1454,7 +1452,7 @@ void FileCatalog::addAndOpenFile (const Glib::ustring& fname) {
|
||||
Thumbnail* tmb = cacheMgr->getEntry (file->get_parse_name());
|
||||
if (tmb) {
|
||||
FileBrowserEntry* entry = new FileBrowserEntry (tmb, file->get_parse_name());
|
||||
previewReadyUI (selectedDirectoryId,entry);
|
||||
previewReady (selectedDirectoryId,entry);
|
||||
// open the file
|
||||
FCOIParams* params = new FCOIParams;
|
||||
params->catalog = this;
|
||||
@@ -1511,7 +1509,9 @@ void FileCatalog::selectionChanged (std::vector<Thumbnail*> tbe) {
|
||||
|
||||
void FileCatalog::exifFilterChanged () {
|
||||
|
||||
currentEFS = filterPanel->getFilter ();
|
||||
// not sure that locking is necessary here...
|
||||
Glib::Mutex::Lock lock(filterMutex);
|
||||
currentEFS = filterPanel->getFilter ();
|
||||
hasValidCurrentEFS = true;
|
||||
fileBrowser->applyFilter (getFilter ());
|
||||
_refreshProgressBar();
|
||||
@@ -1557,9 +1557,11 @@ bool FileCatalog::Query_key_pressed (GdkEventKey *event){
|
||||
FileCatalog::buttonQueryClearPressed ();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileCatalog::updateFBQueryTB (bool singleRow) {
|
||||
@@ -1625,9 +1627,11 @@ bool FileCatalog::BrowsePath_key_pressed (GdkEventKey *event){
|
||||
BrowsePath->select_region(BrowsePath->get_text_length(), BrowsePath->get_text_length());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileCatalog::tbLeftPanel_1_visible (bool visible){
|
||||
@@ -1806,6 +1810,7 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) {
|
||||
FileCatalog::buttonBrowsePathPressed ();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -133,6 +133,7 @@ class FileCatalog : public Gtk::VBox,
|
||||
Gtk::Button* zoomInButton;
|
||||
Gtk::Button* zoomOutButton;
|
||||
|
||||
Glib::Mutex filterMutex;
|
||||
ExifFilterSettings dirEFS;
|
||||
ExifFilterSettings currentEFS;
|
||||
bool hasValidCurrentEFS;
|
||||
@@ -172,21 +173,20 @@ class FileCatalog : public Gtk::VBox,
|
||||
void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile="");
|
||||
void closeDir ();
|
||||
void refreshEditedState (const std::set<Glib::ustring>& efiles);
|
||||
|
||||
|
||||
// previewloaderlistener interface
|
||||
void previewReadyUI (int dir_id, FileBrowserEntry* fdn);
|
||||
void previewReady (int dir_id, FileBrowserEntry* fdn);
|
||||
void previewsFinished (int dir_id);
|
||||
void previewReady (int dir_id, FileBrowserEntry* fdn);
|
||||
void previewsFinished (int dir_id);
|
||||
void previewsFinishedUI ();
|
||||
void _refreshProgressBar ();
|
||||
|
||||
// filterpanel interface
|
||||
void exifFilterChanged ();
|
||||
|
||||
// exportpanel interface
|
||||
void exportRequested();
|
||||
|
||||
Glib::ustring lastSelectedDir () { return selectedDirectory; }
|
||||
// filterpanel interface
|
||||
void exifFilterChanged ();
|
||||
|
||||
// exportpanel interface
|
||||
void exportRequested();
|
||||
|
||||
Glib::ustring lastSelectedDir () { return selectedDirectory; }
|
||||
void setEnabled (bool e); // if not enabled, it does not open image
|
||||
void enableTabMode(bool enable); // sets progress bar
|
||||
|
||||
@@ -210,18 +210,18 @@ class FileCatalog : public Gtk::VBox,
|
||||
void setImageAreaToolListener (ImageAreaToolListener* l) { iatlistener = l; }
|
||||
void setDirBrowserRemoteInterface (DirBrowserRemoteInterface* l) { dirlistener = l; }
|
||||
|
||||
void setFilterPanel (FilterPanel* fpanel);
|
||||
void setExportPanel (ExportPanel* expanel);
|
||||
void exifInfoButtonToggled();
|
||||
void setFilterPanel (FilterPanel* fpanel);
|
||||
void setExportPanel (ExportPanel* expanel);
|
||||
void exifInfoButtonToggled();
|
||||
void categoryButtonToggled (Gtk::ToggleButton* b, bool isMouseClick);
|
||||
bool capture_event(GdkEventButton* event);
|
||||
void filterChanged ();
|
||||
void runFilterDialog ();
|
||||
|
||||
void on_realize();
|
||||
void reparseDirectory ();
|
||||
void reparseDirectory ();
|
||||
void _openImage (std::vector<Thumbnail*> tmb);
|
||||
|
||||
|
||||
void zoomIn ();
|
||||
void zoomOut ();
|
||||
|
||||
|
@@ -87,6 +87,7 @@ FilePanel::FilePanel () : parent(NULL) {
|
||||
fileCatalog->setFilterPanel (filterPanel);
|
||||
fileCatalog->setExportPanel (exportPanel);
|
||||
fileCatalog->setImageAreaToolListener (tpc);
|
||||
fileCatalog->fileBrowser->setBatchPParamsChangeListener (tpc);
|
||||
|
||||
//------------------
|
||||
|
||||
@@ -134,6 +135,7 @@ void FilePanel::setAspect () {
|
||||
|
||||
void FilePanel::init () {
|
||||
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
dirBrowser->fillDirTree ();
|
||||
placesBrowser->refreshPlacesList ();
|
||||
|
||||
@@ -170,40 +172,49 @@ bool FilePanel::fileSelected (Thumbnail* thm) {
|
||||
|
||||
ProgressConnector<rtengine::InitialImage*> *ld = new ProgressConnector<rtengine::InitialImage*>();
|
||||
ld->startFunc (sigc::bind(sigc::ptr_fun(&rtengine::InitialImage::load), thm->getFileName (), thm->getType()==FT_Raw, &error, parent->getProgressListener()),
|
||||
sigc::bind(sigc::mem_fun(*this,&FilePanel::imageLoaded), thm, ld) );
|
||||
sigc::bind(sigc::mem_fun(*this,&FilePanel::imageLoaded), thm, ld) );
|
||||
return true;
|
||||
}
|
||||
bool FilePanel::imageLoaded( Thumbnail* thm, ProgressConnector<rtengine::InitialImage*> *pc ){
|
||||
|
||||
if (pc->returnValue() && thm) {
|
||||
|
||||
if (pc->returnValue() && thm) {
|
||||
|
||||
if (options.tabbedUI) {
|
||||
EditorPanel* epanel = Gtk::manage (new EditorPanel ());
|
||||
EditorPanel* epanel;
|
||||
{
|
||||
GThreadLock lock; // Acquiring the GUI... not sure that it's necessary, but it shouldn't harm
|
||||
epanel = Gtk::manage (new EditorPanel ());
|
||||
parent->addEditorPanel (epanel,Glib::path_get_basename (thm->getFileName()));
|
||||
}
|
||||
epanel->open(thm, pc->returnValue() );
|
||||
} else {
|
||||
{
|
||||
GThreadLock lock; // Acquiring the GUI... not sure that it's necessary, but it shouldn't harm
|
||||
parent->SetEditorCurrent();
|
||||
parent->epanel->open(thm, pc->returnValue() );
|
||||
}
|
||||
parent->epanel->open(thm, pc->returnValue() );
|
||||
}
|
||||
} else {
|
||||
Glib::ustring msg_ = Glib::ustring("<b>") + M("MAIN_MSG_CANNOTLOAD") + " \"" + thm->getFileName() + "\" .\n</b>";
|
||||
Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
msgd.run ();
|
||||
}
|
||||
delete pc;
|
||||
|
||||
} else {
|
||||
Glib::ustring msg_ = Glib::ustring("<b>") + M("MAIN_MSG_CANNOTLOAD") + " \"" + thm->getFileName() + "\" .\n</b>";
|
||||
Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
msgd.run ();
|
||||
}
|
||||
delete pc;
|
||||
|
||||
parent->setProgress(0.);
|
||||
parent->setProgressStr("");
|
||||
thm->imageLoad( false );
|
||||
{
|
||||
GThreadLock lock; // Acquiring the GUI... not sure that it's necessary, but it shouldn't harm
|
||||
parent->setProgress(0.);
|
||||
parent->setProgressStr("");
|
||||
}
|
||||
thm->imageLoad( false );
|
||||
|
||||
return false; // MUST return false from idle function
|
||||
return false; // MUST return false from idle function
|
||||
}
|
||||
|
||||
void FilePanel::saveOptions () {
|
||||
|
||||
int winW, winH;
|
||||
parent->get_size(winW, winH);
|
||||
int winW, winH;
|
||||
parent->get_size(winW, winH);
|
||||
options.dirBrowserWidth = dirpaned->get_position ();
|
||||
options.dirBrowserHeight = placespaned->get_position ();
|
||||
options.browserToolPanelWidth = winW - get_position();
|
||||
@@ -262,6 +273,7 @@ bool FilePanel::handleShortcutKey (GdkEventKey* event) {
|
||||
|
||||
void FilePanel::loadingThumbs(Glib::ustring str, double rate)
|
||||
{
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
if( !str.empty())
|
||||
parent->setProgressStr(str);
|
||||
parent->setProgress( rate );
|
||||
|
@@ -28,6 +28,11 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
#if TRACE_MYRWMUTEX==1 && !defined NDEBUG
|
||||
unsigned int MyReaderLock::readerLockCounter = 0;
|
||||
unsigned int MyWriterLock::writerLockCounter = 0;
|
||||
#endif
|
||||
|
||||
Glib::ustring escapeHtmlChars(const Glib::ustring &src) {
|
||||
|
||||
// Sources chars to be escaped
|
||||
|
452
rtgui/guiutils.h
452
rtgui/guiutils.h
@@ -20,7 +20,10 @@
|
||||
#define __GUI_UTILS_
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include <glibmm.h>
|
||||
#include "../rtengine/rtengine.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
Glib::ustring escapeHtmlChars(const Glib::ustring &src);
|
||||
bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference=true);
|
||||
@@ -74,6 +77,455 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef NDEBUG
|
||||
// We don't trace mutex
|
||||
#undef TRACE_MYRWMUTEX
|
||||
#define TRACE_MYRWMUTEX 0
|
||||
#endif
|
||||
|
||||
|
||||
// Uncomment this if you want to bypass the CMakeList options and force the values
|
||||
// Of course, DO NOT COMMIT! :)
|
||||
|
||||
//#undef PROTECT_VECTORS
|
||||
//#define PROTECT_VECTORS 1
|
||||
//#undef TRACE_MYRWMUTEX
|
||||
//#define TRACE_MYRWMUTEX 1
|
||||
|
||||
|
||||
/**
|
||||
* @brief Custom RWLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
|
||||
*
|
||||
* It may be slower, but thread safe!
|
||||
*/
|
||||
class MyRWMutex {
|
||||
public:
|
||||
Glib::Mutex handlerMutex;
|
||||
Glib::Cond access;
|
||||
size_t writerCount;
|
||||
size_t readerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
Glib::ustring lastWriterFile;
|
||||
int lastWriterLine;
|
||||
// Unfortunately, ownerThread may not be the culprit of a deadlock, it can be another concurrent Reader...
|
||||
void* ownerThread;
|
||||
|
||||
MyRWMutex() : writerCount(0), readerCount(0), lastWriterLine(0), ownerThread(NULL) {}
|
||||
#else
|
||||
MyRWMutex() : writerCount(0), readerCount(0) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Custom ReaderLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
|
||||
*
|
||||
*/
|
||||
class MyReaderLock {
|
||||
|
||||
MyRWMutex& rwMutex;
|
||||
bool locked;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
static unsigned int readerLockCounter;
|
||||
int locknumber;
|
||||
|
||||
public:
|
||||
inline MyReaderLock(MyRWMutex& mutex, const char* name, const char* file, const int line) : rwMutex(mutex), locked(false), locknumber(0)
|
||||
#else
|
||||
public:
|
||||
inline MyReaderLock(MyRWMutex& mutex) : rwMutex(mutex)
|
||||
#endif
|
||||
|
||||
{
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
locknumber = readerLockCounter++;
|
||||
void* thread = Glib::Thread::self();
|
||||
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - R";
|
||||
#endif
|
||||
|
||||
if (!rwMutex.writerCount) {
|
||||
// There's no writer operating, we can increment the writer count which will lock writers
|
||||
++rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " ++ new owner";
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// The writer count is non null, but we can be the owner of the writer lock
|
||||
// It will be the case if the reader count is non null too.
|
||||
if (!rwMutex.readerCount) {
|
||||
// the mutex is in real write mode, we're waiting to see it null
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
|
||||
#endif
|
||||
while (rwMutex.writerCount)
|
||||
rwMutex.access.wait(rwMutex.handlerMutex);
|
||||
++rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = file;
|
||||
rwMutex.lastWriterLine = line;
|
||||
rwMutex.ownerThread = thread;
|
||||
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - R ++ new owner";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// then we can increment the reader count
|
||||
++rwMutex.readerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " - ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
|
||||
inline void acquire(const char* file, const int line)
|
||||
#else
|
||||
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
|
||||
inline void acquire()
|
||||
#endif
|
||||
{
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (!locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - R (lock)";
|
||||
#endif
|
||||
|
||||
if (!rwMutex.writerCount) {
|
||||
// There's no writer operating, we can increment the writer count which will lock writers
|
||||
++rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " ++ new owner";
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// The writer count is non null, but a reader can be the owner of the writer lock,
|
||||
// it will be the case if the reader count is non null too.
|
||||
if (!rwMutex.readerCount) {
|
||||
// the mutex is in real write mode, we're waiting to see it null
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
|
||||
#endif
|
||||
while (rwMutex.writerCount)
|
||||
rwMutex.access.wait(rwMutex.handlerMutex);
|
||||
++rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = file;
|
||||
rwMutex.lastWriterLine = line;
|
||||
rwMutex.ownerThread = thread;
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - R (lock) ++ new owner";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// then we can increment the reader count
|
||||
++rwMutex.readerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " - ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already locked by this object - R (lock)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
inline ~MyReaderLock() {
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
// decrement the writer number first
|
||||
--rwMutex.readerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << " / unlocking - R - ReaderCount: " << rwMutex.readerCount;
|
||||
#endif
|
||||
|
||||
if (!rwMutex.readerCount) {
|
||||
// no more reader, so we decrement the writer count
|
||||
--rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = "";
|
||||
rwMutex.lastWriterLine = 0;
|
||||
rwMutex.ownerThread = NULL;
|
||||
std::cout << " -- new owner possible!" << " >>> ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount;
|
||||
#endif
|
||||
// and signal the next waiting reader/writer that it's free
|
||||
rwMutex.access.broadcast();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already unlocked by this object - R" << std::endl;
|
||||
#endif
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
|
||||
inline void release(const char* file, const int line)
|
||||
#else
|
||||
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
|
||||
inline void release()
|
||||
#endif
|
||||
{
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
// decrement the writer number first
|
||||
--rwMutex.readerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << " / unlocking - R (release) - ReaderCount: " << rwMutex.readerCount;
|
||||
#endif
|
||||
|
||||
if (!rwMutex.readerCount) {
|
||||
// no more reader, so we decrement the writer count
|
||||
--rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = "";
|
||||
rwMutex.lastWriterLine = 0;
|
||||
rwMutex.ownerThread = NULL;
|
||||
std::cout << " -- new owner possible!" << " >>> ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount;
|
||||
#endif
|
||||
// and signal the next waiting reader/writer that it's free
|
||||
rwMutex.access.broadcast();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = false;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already unlocked - R (release)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Custom WriterLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
|
||||
*
|
||||
*/
|
||||
class MyWriterLock {
|
||||
|
||||
MyRWMutex& rwMutex;
|
||||
bool locked;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
static unsigned int writerLockCounter;
|
||||
int locknumber;
|
||||
public:
|
||||
inline MyWriterLock(MyRWMutex& mutex, const char* name, const char* file, const int line) : rwMutex(mutex), locked(false), locknumber(0)
|
||||
#else
|
||||
public:
|
||||
inline MyWriterLock(MyRWMutex& mutex) : rwMutex(mutex)
|
||||
#endif
|
||||
{
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
locknumber = writerLockCounter++;
|
||||
void* thread = Glib::Thread::self();
|
||||
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - W";
|
||||
#endif
|
||||
|
||||
if (rwMutex.writerCount) {
|
||||
// The writer count is non null, so we have to wait for it to be null again
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
|
||||
#endif
|
||||
while (rwMutex.writerCount)
|
||||
rwMutex.access.wait(rwMutex.handlerMutex);
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W";
|
||||
#endif
|
||||
}
|
||||
// then we can increment the writer count
|
||||
++rwMutex.writerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = file;
|
||||
rwMutex.lastWriterLine = line;
|
||||
rwMutex.ownerThread = thread;
|
||||
std::cout << " ++ new owner <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
|
||||
inline void acquire(const char* file, const int line)
|
||||
#else
|
||||
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
|
||||
inline void acquire()
|
||||
#endif
|
||||
{
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (!locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W (lock)";
|
||||
#endif
|
||||
|
||||
if (rwMutex.writerCount) {
|
||||
// The writer count is non null, so we have to wait for it to be null again
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
|
||||
#endif
|
||||
while (rwMutex.writerCount)
|
||||
rwMutex.access.wait(rwMutex.handlerMutex);
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W (lock)";
|
||||
#endif
|
||||
}
|
||||
// then we can increment the reader count
|
||||
++rwMutex.writerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = file;
|
||||
rwMutex.lastWriterLine = line;
|
||||
rwMutex.ownerThread = thread;
|
||||
std::cout << " ++ new owner <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already locked by this object - W (lock)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
inline ~MyWriterLock() {
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
// decrement the writer number first
|
||||
--rwMutex.writerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << " / unlocking - W";
|
||||
#endif
|
||||
|
||||
if (!rwMutex.writerCount) {
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = "";
|
||||
rwMutex.lastWriterLine = 0;
|
||||
rwMutex.ownerThread = NULL;
|
||||
std::cout << " -- new owner possible!";
|
||||
#endif
|
||||
// The writer count is null again, so we can wake up the next writer or reader
|
||||
rwMutex.access.broadcast();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already unlocked by this object - W" << std::endl;
|
||||
#endif
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
|
||||
inline void release(const char* file, const int line)
|
||||
#else
|
||||
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
|
||||
inline void release()
|
||||
#endif
|
||||
{
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
// decrement the writer number first
|
||||
--rwMutex.writerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << " / unlocking - W (release)";
|
||||
#endif
|
||||
|
||||
if (!rwMutex.writerCount) {
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = "";
|
||||
rwMutex.lastWriterLine = 0;
|
||||
rwMutex.ownerThread = NULL;
|
||||
std::cout << " -- new owner possible!";
|
||||
#endif
|
||||
// The writer count is null again, so we can wake up the next writer or reader
|
||||
rwMutex.access.broadcast();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = false;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already unlocked by this object - W (release)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
#define MYREADERLOCK(ln, e) MyReaderLock ln(e, #e, __FILE__, __LINE__);
|
||||
#define MYWRITERLOCK(ln, e) MyWriterLock ln(e, #e, __FILE__, __LINE__);
|
||||
#define MYREADERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__);
|
||||
#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__);
|
||||
#define MYREADERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__);
|
||||
#define MYWRITERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__);
|
||||
#else
|
||||
#define MYREADERLOCK(ln, e) MyReaderLock ln(e);
|
||||
#define MYWRITERLOCK(ln, e) MyWriterLock ln(e);
|
||||
#define MYREADERLOCK_ACQUIRE(ln) ln.acquire();
|
||||
#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire();
|
||||
#define MYREADERLOCK_RELEASE(ln) ln.release();
|
||||
#define MYWRITERLOCK_RELEASE(ln) ln.release();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief subclass of Gtk::ScrolledWindow in order to handle the scrollwheel
|
||||
*/
|
||||
|
@@ -353,6 +353,9 @@ void HistogramRGBArea::renderRGBMarks (int r, int g, int b) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Mostly not necessary, but should be in some case
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
|
||||
Glib::RefPtr<Gdk::Window> window = get_window();
|
||||
int winx, winy, winw, winh, wind;
|
||||
window->get_geometry(winx, winy, winw, winh, wind);
|
||||
@@ -420,8 +423,6 @@ void HistogramRGBArea::renderRGBMarks (int r, int g, int b) {
|
||||
|
||||
int histrgbupdate (void* data) {
|
||||
|
||||
gdk_threads_enter ();
|
||||
|
||||
HistogramRGBAreaIdleHelper* harih = static_cast<HistogramRGBAreaIdleHelper*>(data);
|
||||
|
||||
if (harih->destroyed) {
|
||||
@@ -429,7 +430,6 @@ int histrgbupdate (void* data) {
|
||||
delete harih;
|
||||
else
|
||||
harih->pending--;
|
||||
gdk_threads_leave ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -437,7 +437,6 @@ int histrgbupdate (void* data) {
|
||||
harih->harea->queue_draw ();
|
||||
|
||||
harih->pending--;
|
||||
gdk_threads_leave ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -453,7 +452,7 @@ void HistogramRGBArea::update (int valh, int rh, int gh, int bh) {
|
||||
}
|
||||
else
|
||||
valid = false;
|
||||
|
||||
|
||||
harih->pending++;
|
||||
g_idle_add (histrgbupdate, harih);
|
||||
}
|
||||
@@ -618,8 +617,9 @@ void HistogramArea::update (LUTu &histRed, LUTu &histGreen, LUTu &histBlue, LUTu
|
||||
}
|
||||
else
|
||||
valid = false;
|
||||
|
||||
|
||||
haih->pending++;
|
||||
// Can be done outside of the GUI thread
|
||||
g_idle_add (histupdateUI, haih);
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "lwbutton.h"
|
||||
#include "guiutils.h"
|
||||
|
||||
LWButton::LWButton (Cairo::RefPtr<Cairo::ImageSurface> i, int aCode, void* aData, Alignment ha, Alignment va, Glib::ustring tooltip)
|
||||
: halign(ha), valign(va), icon(i), state(Normal), listener(NULL), actionCode(aCode), actionData(aData), toolTip(tooltip) {
|
||||
@@ -145,6 +146,7 @@ bool LWButton::releaseNotify (int x, int y) {
|
||||
|
||||
void LWButton::redraw (Cairo::RefPtr<Cairo::Context> context) {
|
||||
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
context->set_line_width (1.0);
|
||||
context->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
|
||||
context->rectangle (xpos+0.5, ypos+0.5, w-1.0, h-1.0);
|
||||
@@ -162,10 +164,10 @@ void LWButton::redraw (Cairo::RefPtr<Cairo::Context> context) {
|
||||
if (state==Pressed_In)
|
||||
dilat++;
|
||||
|
||||
if (icon) {
|
||||
context->set_source (icon, xpos+dilat, ypos+dilat);
|
||||
context->paint ();
|
||||
}
|
||||
if (icon) {
|
||||
context->set_source (icon, xpos+dilat, ypos+dilat);
|
||||
context->paint ();
|
||||
}
|
||||
}
|
||||
|
||||
void LWButton::getAlignment (Alignment& ha, Alignment& va) {
|
||||
|
@@ -25,6 +25,7 @@ class LWButton;
|
||||
class LWButtonListener {
|
||||
|
||||
public:
|
||||
virtual ~LWButtonListener () {}
|
||||
virtual void buttonPressed (LWButton* button, int actionCode, void* actionData) {}
|
||||
virtual void redrawNeeded (LWButton* button) {}
|
||||
};
|
||||
|
@@ -85,7 +85,7 @@ void LWButtonSet::arrangeButtons (int x, int y, int w, int h) {
|
||||
|
||||
void LWButtonSet::move (int nx, int ny) {
|
||||
|
||||
for (size_t i=0; i<buttons.size(); i++) {
|
||||
for (size_t i=0; i<buttons.size(); i++) {
|
||||
int x, y;
|
||||
buttons[i]->getPosition (x, y);
|
||||
buttons[i]->setPosition (x+nx-ax, y+ny-ay);
|
||||
@@ -97,7 +97,7 @@ void LWButtonSet::move (int nx, int ny) {
|
||||
|
||||
void LWButtonSet::redraw (Cairo::RefPtr<Cairo::Context> context) {
|
||||
|
||||
for (size_t i=0; i<buttons.size(); i++)
|
||||
for (size_t i=0; i<buttons.size(); i++)
|
||||
buttons[i]->redraw (context);
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@
|
||||
// This file is for your program, I won't touch it again!
|
||||
|
||||
#include "config.h"
|
||||
#include <glibmm/thread.h>
|
||||
#include <gtkmm.h>
|
||||
#include <giomm.h>
|
||||
#include <iostream>
|
||||
@@ -53,6 +54,22 @@ Glib::ustring creditsPath;
|
||||
Glib::ustring licensePath;
|
||||
Glib::ustring argv1;
|
||||
bool simpleEditor;
|
||||
Glib::Thread* mainThread;
|
||||
|
||||
|
||||
// This recursive mutex will be used by g_thread_enter/leave instead of a simple mutex
|
||||
static Glib::RecMutex myGdkRecMutex;
|
||||
|
||||
static void myGdkLockEnter() { myGdkRecMutex.lock(); }
|
||||
static void myGdkLockLeave() {
|
||||
// Automatic gdk_flush for non main tread
|
||||
#if AUTO_GDK_FLUSH
|
||||
if (Glib::Thread::self() != mainThread) {
|
||||
gdk_flush();
|
||||
}
|
||||
#endif
|
||||
myGdkRecMutex.unlock();
|
||||
}
|
||||
|
||||
/* Process line command options
|
||||
* Returns
|
||||
@@ -105,9 +122,12 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
Glib::thread_init();
|
||||
gdk_threads_set_lock_functions(G_CALLBACK(myGdkLockEnter), ((GCallback) (myGdkLockLeave)));
|
||||
gdk_threads_init();
|
||||
Gio::init ();
|
||||
|
||||
mainThread = Glib::Thread::self();
|
||||
|
||||
Options::load ();
|
||||
extProgStore->init();
|
||||
SoundManager::init();
|
||||
@@ -158,9 +178,8 @@ int main(int argc, char **argv)
|
||||
printf("Error: no default settings to update!\n");
|
||||
#endif
|
||||
|
||||
|
||||
RTWindow *rtWindow = new class RTWindow();
|
||||
gdk_threads_enter ();
|
||||
RTWindow *rtWindow = new class RTWindow();
|
||||
|
||||
// alerting users if the default raw and image profiles are missing
|
||||
if (options.is_defProfRawMissing()) {
|
||||
|
@@ -806,6 +806,7 @@ void MyDiagonalCurve::updateBackgroundHistogram (LUTu & hist) {
|
||||
bghistvalid = false;
|
||||
|
||||
mcih->pending++;
|
||||
// Can be done outside of the GUI thread
|
||||
g_idle_add (diagonalmchistupdateUI, mcih);
|
||||
|
||||
}
|
||||
|
@@ -250,6 +250,8 @@ void Options::setDefaults () {
|
||||
version = "0.0.0.0"; // temporary value; will be correctly set in RTWindow::on_realize
|
||||
thumbSize = 240;
|
||||
thumbSizeTab = 80;
|
||||
thumbSizeQueue = 100;
|
||||
sameThumbSize = true; // preferring speed of switch between file browser and single editor tab
|
||||
showHistory = true;
|
||||
showFilePanelState = 0; // Not used anymore ; was the thumb strip state
|
||||
showInfo = true;
|
||||
@@ -588,6 +590,8 @@ if (keyFile.has_group ("Profiles")) {
|
||||
if (keyFile.has_group ("File Browser")) {
|
||||
if (keyFile.has_key ("File Browser", "ThumbnailSize")) thumbSize = keyFile.get_integer ("File Browser", "ThumbnailSize");
|
||||
if (keyFile.has_key ("File Browser", "ThumbnailSizeTab")) thumbSizeTab = keyFile.get_integer ("File Browser", "ThumbnailSizeTab");
|
||||
if (keyFile.has_key ("File Browser", "ThumbnailSizeQueue")) thumbSizeQueue = keyFile.get_integer ("File Browser", "ThumbnailSizeQueue");
|
||||
if (keyFile.has_key ("File Browser", "SameThumbSize")) sameThumbSize = keyFile.get_integer ("File Browser", "SameThumbSize");
|
||||
if (keyFile.has_key ("File Browser", "BrowseOnlyRaw")) fbOnlyRaw = keyFile.get_boolean ("File Browser", "BrowseOnlyRaw");
|
||||
if (keyFile.has_key ("File Browser", "BrowserShowsDate")) fbShowDateTime = keyFile.get_boolean ("File Browser", "BrowserShowsDate");
|
||||
if (keyFile.has_key ("File Browser", "BrowserShowsExif")) fbShowBasicExif = keyFile.get_boolean ("File Browser", "BrowserShowsExif");
|
||||
@@ -816,6 +820,8 @@ int Options::saveToFile (Glib::ustring fname) {
|
||||
keyFile.set_boolean ("File Browser", "BrowserShowsHidden", fbShowHidden);
|
||||
keyFile.set_integer ("File Browser", "ThumbnailSize", thumbSize);
|
||||
keyFile.set_integer ("File Browser", "ThumbnailSizeTab", thumbSizeTab);
|
||||
keyFile.set_integer ("File Browser", "ThumbnailSizeQueue", thumbSizeQueue);
|
||||
keyFile.set_integer ("File Browser", "SameThumbSize", sameThumbSize);
|
||||
keyFile.set_integer ("File Browser", "MaxPreviewHeight", maxThumbnailHeight);
|
||||
keyFile.set_integer ("File Browser", "MaxCacheEntries", maxCacheEntries);
|
||||
Glib::ArrayHandle<Glib::ustring> pext = parseExtensions;
|
||||
|
@@ -122,7 +122,8 @@ class Options {
|
||||
bool multiUser;
|
||||
static Glib::ustring rtdir;
|
||||
Glib::ustring version;
|
||||
int thumbSize,thumbSizeTab;
|
||||
int thumbSize,thumbSizeTab, thumbSizeQueue;
|
||||
bool sameThumbSize; // Will use only one thumb size for the file browser and the single editor tab, and avoid recomputing them
|
||||
bool showHistory;
|
||||
int showFilePanelState; // 0: normal, 1: maximized, 2: normal, 3: hidden
|
||||
bool showInfo;
|
||||
|
@@ -26,9 +26,18 @@
|
||||
class PParamsChangeListener {
|
||||
|
||||
public:
|
||||
virtual ~PParamsChangeListener() {}
|
||||
virtual void procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited=NULL) {}
|
||||
virtual void clearParamChanges () {}
|
||||
};
|
||||
|
||||
class BatchPParamsChangeListener {
|
||||
|
||||
public:
|
||||
virtual ~BatchPParamsChangeListener() {}
|
||||
virtual void beginBatchPParamsChange(int numberOfEntries) {}
|
||||
virtual void endBatchPParamsChange() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -23,8 +23,8 @@
|
||||
using namespace rtengine;
|
||||
using namespace rtengine::procparams;
|
||||
|
||||
PreviewHandler::PreviewHandler () : image(NULL) {
|
||||
|
||||
PreviewHandler::PreviewHandler () : image(NULL), previewScale(1.) {
|
||||
|
||||
pih = new PreviewHandlerIdleHelper;
|
||||
pih->phandler = this;
|
||||
pih->destroyed = false;
|
||||
|
@@ -26,6 +26,7 @@
|
||||
class PreviewListener {
|
||||
|
||||
public:
|
||||
virtual ~PreviewListener () {}
|
||||
virtual void previewImageChanged () {}
|
||||
};
|
||||
|
||||
@@ -43,7 +44,7 @@ class PreviewHandler : public rtengine::PreviewImageListener {
|
||||
friend int imageReadyUI (void* data);
|
||||
|
||||
protected:
|
||||
rtengine::IImage8* image;
|
||||
rtengine::IImage8* image;
|
||||
rtengine::procparams::CropParams cropParams;
|
||||
double previewScale;
|
||||
PreviewHandlerIdleHelper* pih;
|
||||
|
@@ -25,9 +25,19 @@
|
||||
class ProfileChangeListener {
|
||||
|
||||
public:
|
||||
virtual ~ProfileChangeListener() {}
|
||||
virtual void profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited=NULL) {}
|
||||
virtual void setDefaults (rtengine::procparams::ProcParams* defparams) {}
|
||||
};
|
||||
|
||||
class BatchProfileChangeListener {
|
||||
|
||||
public:
|
||||
virtual ~BatchProfileChangeListener() {}
|
||||
virtual void beginBatchProfileChange(int numberOfEntries) {}
|
||||
virtual void endBatchProfileChange() {}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -58,19 +58,25 @@ ThumbBrowserBase::ThumbBrowserBase ()
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::scrollChanged () {
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
{
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
fd[i]->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value()));
|
||||
}
|
||||
|
||||
internal.setPosition ((int)(hscroll.get_value()), (int)(vscroll.get_value()));
|
||||
|
||||
if (!internal.isDirty()) {
|
||||
if (!internal.isDirty()) {
|
||||
internal.setDirty ();
|
||||
internal.queue_draw ();
|
||||
// gdk_window_process_updates (get_window()->gobj(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::scroll (int direction) {
|
||||
// GUI already acquired when here
|
||||
if (arrangement==TB_Vertical)
|
||||
vscroll.set_value (vscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * vscroll.get_adjustment()->get_step_increment());
|
||||
else
|
||||
@@ -78,6 +84,7 @@ void ThumbBrowserBase::scroll (int direction) {
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::scrollPage (int direction) {
|
||||
// GUI already acquired when here
|
||||
if (arrangement==TB_Vertical)
|
||||
vscroll.set_value (vscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * vscroll.get_adjustment()->get_page_increment());
|
||||
else
|
||||
@@ -107,6 +114,9 @@ void ThumbBrowserBase::internalAreaResized (Gtk::Allocation& req) {
|
||||
|
||||
void ThumbBrowserBase::configScrollBars () {
|
||||
|
||||
// HOMBRE:DELETE ME?
|
||||
GThreadLock tLock; // Acquire the GUI
|
||||
|
||||
if (inW>0 && inH>0) {
|
||||
|
||||
int iw = internal.get_width ();
|
||||
@@ -136,10 +146,14 @@ void ThumbBrowserBase::configScrollBars () {
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::arrangeFiles () {
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::ReaderLock l(entryRW);
|
||||
#endif
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
// GUI already locked by ::redraw, the only caller of this method for now.
|
||||
// We could lock it one more time, there's no harm excepted (negligible) speed penalty
|
||||
//GThreadLock lock;
|
||||
|
||||
int N = fd.size ();
|
||||
// apply filter
|
||||
@@ -152,7 +166,7 @@ void ThumbBrowserBase::arrangeFiles () {
|
||||
if (!fd[i]->filtered && fd[i]->getMinimalHeight() > rowHeight)
|
||||
rowHeight = fd[i]->getMinimalHeight ();
|
||||
|
||||
if (arrangement==TB_Horizontal) {
|
||||
if (arrangement==TB_Horizontal) {
|
||||
|
||||
int numOfRows = 1;
|
||||
// if (rowHeight>0) {
|
||||
@@ -183,6 +197,10 @@ void ThumbBrowserBase::arrangeFiles () {
|
||||
}
|
||||
currx += maxw;
|
||||
}
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK_RELEASE(l);
|
||||
#endif
|
||||
// This will require a Writer access
|
||||
resizeThumbnailArea (currx, numOfRows*rowHeight);
|
||||
}
|
||||
else {
|
||||
@@ -234,13 +252,17 @@ void ThumbBrowserBase::arrangeFiles () {
|
||||
if (currx>0) // there were thumbnails placed in the row
|
||||
curry += rowHeight;
|
||||
}
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK_RELEASE(l);
|
||||
#endif
|
||||
// This will require a Writer access
|
||||
resizeThumbnailArea (colsWidth, curry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ThumbBrowserBase::Internal::on_realize()
|
||||
{
|
||||
void ThumbBrowserBase::Internal::on_realize() {
|
||||
// Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave)
|
||||
Cairo::FontOptions cfo;
|
||||
cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
|
||||
get_pango_context()->set_cairo_font_options (cfo);
|
||||
@@ -255,12 +277,20 @@ void ThumbBrowserBase::Internal::on_realize()
|
||||
}
|
||||
|
||||
bool ThumbBrowserBase::Internal::on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) {
|
||||
// Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave)
|
||||
Glib::ustring ttip = "";
|
||||
|
||||
{
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, parent->entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<parent->fd.size(); i++)
|
||||
if (parent->fd[i]->drawable && parent->fd[i]->inside (x, y)) {
|
||||
ttip = parent->fd[i]->getToolTip (x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ttip!="") {
|
||||
tooltip->set_text (ttip);
|
||||
return true;
|
||||
@@ -270,8 +300,8 @@ bool ThumbBrowserBase::Internal::on_query_tooltip (int x, int y, bool keyboard_t
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::styleChanged (const Glib::RefPtr<Gtk::Style>& style) {
|
||||
|
||||
refreshThumbImages ();
|
||||
// GUI will be acquired by refreshThumbImages
|
||||
refreshThumbImages ();
|
||||
}
|
||||
|
||||
ThumbBrowserBase::Internal::Internal () : ofsX(0), ofsY(0), parent(NULL), dirty(true) {
|
||||
@@ -287,10 +317,12 @@ void ThumbBrowserBase::Internal::setPosition (int x, int y) {
|
||||
}
|
||||
|
||||
bool ThumbBrowserBase::Internal::on_key_press_event (GdkEventKey* event) {
|
||||
// Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave)
|
||||
return parent->keyPressed (event);
|
||||
}
|
||||
|
||||
bool ThumbBrowserBase::Internal::on_button_press_event (GdkEventButton* event) {
|
||||
// Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave)
|
||||
grab_focus ();
|
||||
|
||||
parent->eventTime = event->time;
|
||||
@@ -310,30 +342,43 @@ bool ThumbBrowserBase::Internal::on_button_press_event (GdkEventButton* event) {
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType type, int state, int clx, int cly, int clw, int clh) {
|
||||
// GUI already acquired
|
||||
|
||||
ThumbBrowserEntryBase* fileDescr = NULL;
|
||||
bool handled = false;
|
||||
|
||||
|
||||
{
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
if (fd[i]->drawable) {
|
||||
if (fd[i]->inside (x, y) && fd[i]->insideWindow (clx, cly, clw, clh))
|
||||
if (fd[i]->inside (x, y) && fd[i]->insideWindow (clx, cly, clw, clh))
|
||||
fileDescr = fd[i];
|
||||
bool b = fd[i]->pressNotify (button, type, state, x, y);
|
||||
handled = handled || b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (handled || (fileDescr && fileDescr->processing))
|
||||
return;
|
||||
|
||||
|
||||
{
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (selected.size()==1 && type==GDK_2BUTTON_PRESS && button==1)
|
||||
doubleClicked (selected[0]);
|
||||
else if (button==1 && type==GDK_BUTTON_PRESS) {
|
||||
if (fileDescr && state & GDK_SHIFT_MASK) {
|
||||
if (fileDescr && (state & GDK_SHIFT_MASK)) {
|
||||
if (selected.empty()) {
|
||||
selected.push_back (fileDescr);
|
||||
fileDescr->selected = true;
|
||||
lastClicked = fileDescr;
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
selectionChanged ();
|
||||
}
|
||||
else {
|
||||
@@ -363,16 +408,19 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ
|
||||
selected[i]->selected = false;
|
||||
selected.clear ();
|
||||
// select thumbnails in the interval
|
||||
for (size_t i=startx; i<=endx; i++) {
|
||||
for (size_t i=startx; i<=endx; i++) {
|
||||
if (!fd[i]->filtered) {
|
||||
fd[i]->selected = true;
|
||||
selected.push_back (fd[i]);
|
||||
}
|
||||
}
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
selectionChanged ();
|
||||
}
|
||||
}
|
||||
else if (fileDescr && state & GDK_CONTROL_MASK) {
|
||||
else if (fileDescr && (state & GDK_CONTROL_MASK)) {
|
||||
std::vector<ThumbBrowserEntryBase*>::iterator i = std::find (selected.begin(), selected.end(), fileDescr);
|
||||
if (i!=selected.end()) {
|
||||
(*i)->selected = false;
|
||||
@@ -383,10 +431,13 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ
|
||||
fileDescr->selected = true;
|
||||
}
|
||||
lastClicked = fileDescr;
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
selectionChanged ();
|
||||
}
|
||||
else {
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
selected[i]->selected = false;
|
||||
selected.clear ();
|
||||
if (fileDescr) {
|
||||
@@ -394,28 +445,36 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ
|
||||
fileDescr->selected = true;
|
||||
}
|
||||
lastClicked = fileDescr;
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
selectionChanged ();
|
||||
}
|
||||
}
|
||||
else if (fileDescr && button==3 && type==GDK_BUTTON_PRESS) {
|
||||
if (!fileDescr->selected) {
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
for (size_t i=0; i<selected.size(); i++)
|
||||
selected[i]->selected = false;
|
||||
selected.clear ();
|
||||
fileDescr->selected = true;
|
||||
selected.push_back (fileDescr);
|
||||
lastClicked = fileDescr;
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
selectionChanged ();
|
||||
}
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK_RELEASE(l);
|
||||
#endif
|
||||
rightClicked (fileDescr);
|
||||
}
|
||||
} // end of MYWRITERLOCK(l, entryRW);
|
||||
|
||||
}
|
||||
|
||||
bool ThumbBrowserBase::Internal::on_expose_event(GdkEventExpose* event) {
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::ReaderLock l(parent->entryRW);
|
||||
#endif
|
||||
// Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave)
|
||||
|
||||
dirty = false;
|
||||
|
||||
@@ -428,6 +487,12 @@ bool ThumbBrowserBase::Internal::on_expose_event(GdkEventExpose* event) {
|
||||
// draw thumbnails
|
||||
Glib::RefPtr<Pango::Context> context = get_pango_context ();
|
||||
context->set_font_description (get_style()->get_font());
|
||||
|
||||
{
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, parent->entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<parent->fd.size() && !dirty; i++) { // if dirty meanwhile, cancel and wait for next redraw
|
||||
if (!parent->fd[i]->drawable || !parent->fd[i]->insideWindow (0, 0, w, h))
|
||||
parent->fd[i]->updatepriority = false;
|
||||
@@ -436,36 +501,56 @@ bool ThumbBrowserBase::Internal::on_expose_event(GdkEventExpose* event) {
|
||||
parent->fd[i]->draw ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbBrowserBase::Internal::on_button_release_event (GdkEventButton* event) {
|
||||
// Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave)
|
||||
int w = get_width();
|
||||
int h = get_height();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, parent->entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<parent->fd.size(); i++)
|
||||
if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) {
|
||||
parent->fd[i]->releaseNotify (event->button, event->type, event->state, (int)event->x, (int)event->y);
|
||||
ThumbBrowserEntryBase* tbe = parent->fd[i];
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK_RELEASE(l);
|
||||
#endif
|
||||
// This will require a Writer access...
|
||||
tbe->releaseNotify (event->button, event->type, event->state, (int)event->x, (int)event->y);
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK_ACQUIRE(l);
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbBrowserBase::Internal::on_motion_notify_event (GdkEventMotion* event) {
|
||||
// Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave)
|
||||
int w = get_width();
|
||||
int h = get_height();
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, parent->entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<parent->fd.size(); i++)
|
||||
if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) {
|
||||
#ifdef WIN32
|
||||
//l.release(); // motionNotify calls the queue, which locks
|
||||
#endif
|
||||
/*#if PROTECT_VECTORS
|
||||
MYREADERLOCK_RELEASE(l); // motionNotify calls the queue, which locks
|
||||
#endif*/
|
||||
parent->fd[i]->motionNotify ((int)event->x, (int)event->y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) {
|
||||
// Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave)
|
||||
|
||||
parent->scroll (event->direction);
|
||||
return true;
|
||||
@@ -474,6 +559,7 @@ bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) {
|
||||
|
||||
void ThumbBrowserBase::redraw () {
|
||||
|
||||
GThreadLock lock;
|
||||
arrangeFiles ();
|
||||
queue_draw ();
|
||||
}
|
||||
@@ -481,30 +567,31 @@ void ThumbBrowserBase::redraw () {
|
||||
void ThumbBrowserBase::zoomChanged (bool zoomIn) {
|
||||
|
||||
int newHeight=0;
|
||||
int optThumbSize=getCurrentThumbSize();
|
||||
int optThumbSize=getThumbnailHeight();
|
||||
if (zoomIn)
|
||||
for (size_t i=0; i<options.thumbnailZoomRatios.size(); i++) {
|
||||
for (size_t i=0; i<options.thumbnailZoomRatios.size(); i++) {
|
||||
newHeight = (int)(options.thumbnailZoomRatios[i] * getMaxThumbnailHeight());
|
||||
if (newHeight > optThumbSize)
|
||||
break;
|
||||
}
|
||||
else
|
||||
for (size_t i=options.thumbnailZoomRatios.size()-1; i>0; i--) {
|
||||
for (size_t i=options.thumbnailZoomRatios.size()-1; i>0; i--) {
|
||||
newHeight = (int)(options.thumbnailZoomRatios[i] * getMaxThumbnailHeight());
|
||||
if (newHeight < optThumbSize)
|
||||
break;
|
||||
}
|
||||
previewHeight = newHeight;
|
||||
if (inTabMode) options.thumbSizeTab = newHeight; else options.thumbSize = newHeight;
|
||||
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
saveThumbnailHeight(newHeight);
|
||||
|
||||
for (size_t i=0; i<fd.size(); i++) fd[i]->resize (previewHeight);
|
||||
}
|
||||
{
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
fd[i]->resize (previewHeight);
|
||||
}
|
||||
|
||||
redraw ();
|
||||
#ifdef WIN32
|
||||
@@ -512,44 +599,46 @@ void ThumbBrowserBase::zoomChanged (bool zoomIn) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int ThumbBrowserBase::getCurrentThumbSize() { return inTabMode ? options.thumbSizeTab : options.thumbSize; }
|
||||
|
||||
void ThumbBrowserBase::refreshThumbImages () {
|
||||
{
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
|
||||
int previewHeight = getCurrentThumbSize();
|
||||
for (size_t i=0; i<fd.size(); i++) fd[i]->resize (previewHeight);
|
||||
}
|
||||
int previewHeight = getThumbnailHeight();
|
||||
{
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<fd.size(); i++) fd[i]->resize (previewHeight);
|
||||
}
|
||||
|
||||
redraw ();
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::refreshQuickThumbImages () {
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<fd.size(); ++i) fd[i]->refreshQuickThumbnailImage ();
|
||||
for (size_t i=0; i<fd.size(); ++i) fd[i]->refreshQuickThumbnailImage ();
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::refreshEditedState (const std::set<Glib::ustring>& efiles) {
|
||||
|
||||
editedFiles = efiles;
|
||||
{
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
fd[i]->framed = editedFiles.find (fd[i]->filename)!=editedFiles.end();
|
||||
}
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
|
||||
void ThumbBrowserBase::setArrangement (Arrangement a) {
|
||||
|
||||
arrangement = a;
|
||||
arrangement = a;
|
||||
redraw ();
|
||||
}
|
||||
|
||||
@@ -557,31 +646,40 @@ void ThumbBrowserBase::enableTabMode(bool enable) {
|
||||
inTabMode = enable;
|
||||
arrangement = inTabMode ? ThumbBrowserBase::TB_Horizontal : ThumbBrowserBase::TB_Vertical;
|
||||
|
||||
if (options.thumbSizeTab!=options.thumbSize) {
|
||||
// TODO: Check for Linux
|
||||
#ifdef WIN32
|
||||
Glib::RWLock::WriterLock l(entryRW);
|
||||
#endif
|
||||
if (!options.sameThumbSize && (options.thumbSizeTab!=options.thumbSize)) {
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
fd[i]->resize (getCurrentThumbSize());
|
||||
for (size_t i=0; i<fd.size(); i++)
|
||||
fd[i]->resize (getThumbnailHeight());
|
||||
}
|
||||
|
||||
redraw ();
|
||||
|
||||
// Scroll to selected position if going into ribbon mode or back
|
||||
// Tab mode is horizontal, file browser is vertical
|
||||
{
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
if (!selected.empty()) {
|
||||
if (inTabMode) {
|
||||
double h=selected[0]->getStartX();
|
||||
hscroll.set_value (min(h, hscroll.get_adjustment()->get_upper()));
|
||||
double h=selected[0]->getStartX();
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK_RELEASE(l);
|
||||
#endif
|
||||
hscroll.set_value (min(h, hscroll.get_adjustment()->get_upper()));
|
||||
} else {
|
||||
double v=selected[0]->getStartY();
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK_RELEASE(l);
|
||||
#endif
|
||||
vscroll.set_value (min(v, vscroll.get_adjustment()->get_upper()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::initEntry (ThumbBrowserEntryBase* entry) {
|
||||
@@ -602,6 +700,10 @@ void ThumbBrowserBase::setScrollPosition (double h, double v) {
|
||||
int ThumbBrowserBase::getEffectiveHeight() {
|
||||
int h=hscroll.get_height() + 2; // have 2 pixels rounding error for scroll bars to appear
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, entryRW);
|
||||
#endif
|
||||
|
||||
// Filtered items do not change in size, so take a non-filtered
|
||||
for (size_t i=0;i<fd.size();i++)
|
||||
if (!fd[i]->filtered) {
|
||||
@@ -610,10 +712,13 @@ int ThumbBrowserBase::getEffectiveHeight() {
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
void ThumbBrowserBase::redrawNeeded (ThumbBrowserEntryBase* entry) {
|
||||
|
||||
// HOMBRE:DELETE ME?
|
||||
GThreadLock tLock; // Acquire the GUI
|
||||
|
||||
if (entry->insideWindow (0, 0, internal.get_width(), internal.get_height())) {
|
||||
if (!internal.isDirty ()) {
|
||||
internal.setDirty ();
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "thumbbrowserentrybase.h"
|
||||
#include <set>
|
||||
#include "options.h"
|
||||
#include "guiutils.h"
|
||||
|
||||
/*
|
||||
* Class handling the list of ThumbBrowserEntry objects and their position in it's allocated space
|
||||
@@ -54,6 +55,8 @@ class ThumbBrowserBase : public Gtk::VBox {
|
||||
|
||||
protected:
|
||||
virtual int getMaxThumbnailHeight() const { return options.maxThumbnailHeight; } // Differs between batch and file
|
||||
virtual void saveThumbnailHeight (int height)=0;
|
||||
virtual int getThumbnailHeight ()=0;
|
||||
|
||||
Internal internal;
|
||||
Gtk::HScrollbar hscroll;
|
||||
@@ -62,7 +65,6 @@ class ThumbBrowserBase : public Gtk::VBox {
|
||||
int inW, inH;
|
||||
|
||||
bool inTabMode; // Tab mode has e.g. different preview heights
|
||||
int getCurrentThumbSize(); // depending on filmstrip/file browser mode
|
||||
|
||||
void resizeThumbnailArea (int w, int h);
|
||||
void internalAreaResized (Gtk::Allocation& req);
|
||||
@@ -80,7 +82,7 @@ class ThumbBrowserBase : public Gtk::VBox {
|
||||
|
||||
int eventTime;
|
||||
|
||||
Glib::RWLock entryRW; // Locks access to following vectors
|
||||
MyRWMutex entryRW; // Locks access to following 'fd' AND 'selected'
|
||||
std::vector<ThumbBrowserEntryBase*> fd;
|
||||
std::vector<ThumbBrowserEntryBase*> selected;
|
||||
ThumbBrowserEntryBase* lastClicked;
|
||||
|
@@ -22,26 +22,18 @@
|
||||
#include "../rtengine/mytime.h"
|
||||
|
||||
ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname)
|
||||
: preh(0), preview(NULL), buttonSet(NULL), exp_width(0), exp_height(0), redrawRequests(0),
|
||||
parent(NULL), filename(fname), exifline(""), datetimeline(""), selected(false),
|
||||
drawable(false),framed(false), processing(false), italicstyle(false),
|
||||
updatepriority(false) {
|
||||
|
||||
shortname = Glib::path_get_basename (fname);
|
||||
dispname = shortname;
|
||||
|
||||
upperMargin = 6;
|
||||
borderWidth = 1;
|
||||
sideMargin = 8;
|
||||
lowerMargin = 8;
|
||||
textGap = 6;
|
||||
|
||||
ofsX = ofsY = 0;
|
||||
}
|
||||
: fnlabw(0), fnlabh(0), dtlabw(0), dtlabh(0), exlabw(0), exlabh(0), prew(0), preh(0),
|
||||
prex(0), prey(0), upperMargin(6), borderWidth(1), textGap(6), sideMargin(8), lowerMargin(8),
|
||||
preview(NULL), dispname(Glib::path_get_basename (fname)), buttonSet(NULL), width(0), height(0),
|
||||
exp_width(0), exp_height(0), startx(0), starty(0), ofsX(0), ofsY(0), redrawRequests(0),
|
||||
parent(NULL), bbSelected(false), bbFramed(false), bbPreview(NULL),
|
||||
thumbnail(NULL), filename(fname), shortname(dispname), exifline(""), datetimeline(""),
|
||||
selected(false), drawable(false), filtered(false), framed(false), processing(false), italicstyle(false),
|
||||
edited(false), recentlysaved(false), updatepriority(false) {}
|
||||
|
||||
ThumbBrowserEntryBase::~ThumbBrowserEntryBase () {
|
||||
|
||||
delete [] preview;
|
||||
if (preview) delete [] preview;
|
||||
delete buttonSet;
|
||||
}
|
||||
|
||||
@@ -259,7 +251,10 @@ void ThumbBrowserEntryBase::getTextSizes (int& infow, int& infoh) {
|
||||
}
|
||||
|
||||
void ThumbBrowserEntryBase::resize (int h) {
|
||||
Glib::RWLock::WriterLock l(lockRW);
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, lockRW);
|
||||
#endif
|
||||
|
||||
height = h;
|
||||
int old_preh = preh, old_width = width;
|
||||
@@ -348,7 +343,9 @@ void ThumbBrowserEntryBase::draw () {
|
||||
if (!drawable || !parent)
|
||||
return;
|
||||
|
||||
Glib::RWLock::ReaderLock l(lockRW); // No resizes, position moves etc. inbetween
|
||||
#if PROTECT_VECTORS
|
||||
MYREADERLOCK(l, lockRW); // No resizes, position moves etc. inbetween
|
||||
#endif
|
||||
|
||||
int bbWidth, bbHeight;
|
||||
if (backBuffer)
|
||||
@@ -376,12 +373,16 @@ void ThumbBrowserEntryBase::draw () {
|
||||
// redraw button set above the thumbnail
|
||||
if (buttonSet) {
|
||||
buttonSet->setColors (selected ? bgs : bgn, selected ? bgn : bgs);
|
||||
buttonSet->redraw (w->get_window()->create_cairo_context());
|
||||
Cairo::RefPtr<Cairo::Context> cc = w->get_window()->create_cairo_context();
|
||||
buttonSet->redraw (cc);
|
||||
}
|
||||
}
|
||||
|
||||
void ThumbBrowserEntryBase::setPosition (int x, int y, int w, int h) {
|
||||
Glib::RWLock::WriterLock l(lockRW);
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, lockRW);
|
||||
#endif
|
||||
|
||||
exp_width = w;
|
||||
exp_height = h;
|
||||
@@ -393,7 +394,10 @@ void ThumbBrowserEntryBase::setPosition (int x, int y, int w, int h) {
|
||||
}
|
||||
|
||||
void ThumbBrowserEntryBase::setOffset (int x, int y) {
|
||||
Glib::RWLock::WriterLock l(lockRW);
|
||||
|
||||
#if PROTECT_VECTORS
|
||||
MYWRITERLOCK(l, lockRW);
|
||||
#endif
|
||||
|
||||
ofsX = -x;
|
||||
ofsY = -y;
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <gtkmm.h>
|
||||
#include "lwbuttonset.h"
|
||||
#include "thumbnail.h"
|
||||
#include "guiutils.h"
|
||||
|
||||
class ThumbBrowserBase;
|
||||
class ThumbBrowserEntryBase {
|
||||
@@ -42,7 +43,7 @@ protected:
|
||||
int lowerMargin;
|
||||
|
||||
|
||||
Glib::RWLock lockRW; // Locks access to all image thumb changing actions
|
||||
MyRWMutex lockRW; // Locks access to all image thumb changing actions
|
||||
|
||||
guint8* preview; // holds the preview image. used in updateBackBuffer. TODO Olli: Make a cache to reduce mem significantly
|
||||
|
||||
|
@@ -48,6 +48,8 @@ public:
|
||||
|
||||
Job():
|
||||
tbe_(0),
|
||||
priority_(NULL),
|
||||
upgrade_(false),
|
||||
listener_(0)
|
||||
{}
|
||||
|
||||
@@ -86,7 +88,7 @@ public:
|
||||
Glib::Cond inactive_;
|
||||
|
||||
void
|
||||
processNextJob(void)
|
||||
processNextJob()
|
||||
{
|
||||
Job j;
|
||||
|
||||
|
@@ -33,13 +33,18 @@
|
||||
|
||||
using namespace rtengine::procparams;
|
||||
|
||||
Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf)
|
||||
Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf, const rtengine::procparams::ProcParams *pparams)
|
||||
: fname(fname), cfs(*cf), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL),
|
||||
pparamsValid(false), needsReProcessing(true),imageLoading(false), lastImg(NULL),
|
||||
lastW(0), lastH(0), lastScale(0), initial_(false) {
|
||||
lastW(0), lastH(0), lastScale(0), initial_(false)
|
||||
{
|
||||
|
||||
cfs.load (getCacheFileName ("data")+".txt");
|
||||
loadProcParams ();
|
||||
if (pparams) {
|
||||
this->pparams = *pparams;
|
||||
pparamsValid = true;
|
||||
}
|
||||
else
|
||||
loadProcParams ();
|
||||
_loadThumbnail ();
|
||||
generateExifDateTimeStrings ();
|
||||
|
||||
@@ -55,25 +60,31 @@ Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageDa
|
||||
setStage(cfs.inTrashOld);
|
||||
}
|
||||
|
||||
delete tpp;
|
||||
tpp = 0;
|
||||
delete tpp;
|
||||
tpp = 0;
|
||||
}
|
||||
|
||||
Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5)
|
||||
Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5, const rtengine::procparams::ProcParams *pparams)
|
||||
: fname(fname), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL), pparamsValid(false),
|
||||
needsReProcessing(true),imageLoading(false), lastImg(NULL),
|
||||
initial_(true) {
|
||||
initial_(true)
|
||||
{
|
||||
|
||||
|
||||
cfs.md5 = md5;
|
||||
_generateThumbnailImage ();
|
||||
loadProcParams ();
|
||||
if (pparams) {
|
||||
this->pparams = *pparams;
|
||||
pparamsValid = true;
|
||||
}
|
||||
else
|
||||
loadProcParams ();
|
||||
cfs.recentlySaved = false;
|
||||
|
||||
initial_ = false;
|
||||
|
||||
delete tpp;
|
||||
tpp = 0;
|
||||
initial_ = false;
|
||||
|
||||
delete tpp;
|
||||
tpp = 0;
|
||||
}
|
||||
|
||||
void Thumbnail::_generateThumbnailImage () {
|
||||
@@ -96,7 +107,7 @@ void Thumbnail::_generateThumbnailImage () {
|
||||
cfs.timeValid = false;
|
||||
|
||||
if (ext.lowercase()=="jpg" || ext.lowercase()=="jpeg") {
|
||||
tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, infoFromImage (fname));
|
||||
tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1);
|
||||
if (tpp)
|
||||
cfs.format = FT_Jpeg;
|
||||
}
|
||||
@@ -106,8 +117,7 @@ void Thumbnail::_generateThumbnailImage () {
|
||||
cfs.format = FT_Png;
|
||||
}
|
||||
else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") {
|
||||
int deg = infoFromImage (fname);
|
||||
tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, deg);
|
||||
tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1);
|
||||
if (tpp)
|
||||
cfs.format = FT_Tiff;
|
||||
}
|
||||
|
@@ -76,8 +76,8 @@ class Thumbnail {
|
||||
Glib::ustring getCacheFileName (Glib::ustring subdir);
|
||||
|
||||
public:
|
||||
Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf);
|
||||
Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5);
|
||||
Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf, const rtengine::procparams::ProcParams *pparams=NULL);
|
||||
Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5, const rtengine::procparams::ProcParams *pparams=NULL);
|
||||
~Thumbnail ();
|
||||
|
||||
bool hasProcParams ();
|
||||
|
@@ -494,8 +494,6 @@ void ToneCurve::autoExpChanged (double expcomp, int bright, int contr, int black
|
||||
nextHlcompr = hlcompr;
|
||||
nextHlcomprthresh = hlcomprthresh;
|
||||
g_idle_add (autoExpChangedUI, this);
|
||||
|
||||
// Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::autoExpComputed_));
|
||||
}
|
||||
|
||||
void ToneCurve::enableAll () {
|
||||
@@ -515,6 +513,7 @@ void ToneCurve::enableAll () {
|
||||
|
||||
bool ToneCurve::autoExpComputed_ () {
|
||||
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
disableListener ();
|
||||
enableAll ();
|
||||
expcomp->setValue (nextExpcomp);
|
||||
|
@@ -580,6 +580,7 @@ bool ToolPanelCoordinator::handleShortcutKey (GdkEventKey* event) {
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::updateVScrollbars (bool hide) {
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
Gtk::PolicyType policy = hide ? Gtk::POLICY_NEVER : Gtk::POLICY_AUTOMATIC;
|
||||
exposurePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy);
|
||||
detailsPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy);
|
||||
@@ -589,9 +590,10 @@ void ToolPanelCoordinator::updateVScrollbars (bool hide) {
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::updateTabsHeader (bool useIcons) {
|
||||
TOITypes type = useIcons ? TOI_ICON : TOI_TEXT;
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
TOITypes type = useIcons ? TOI_ICON : TOI_TEXT;
|
||||
|
||||
toiE->switchTo(type);
|
||||
toiE->switchTo(type);
|
||||
toiD->switchTo(type);
|
||||
toiC->switchTo(type);
|
||||
toiT->switchTo(type);
|
||||
@@ -609,6 +611,7 @@ void ToolPanelCoordinator::updateTabsUsesIcons (bool useIcons) {
|
||||
}
|
||||
|
||||
void ToolPanelCoordinator::toolSelected (ToolMode tool) {
|
||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||
switch (tool) {
|
||||
case TMCropSelect:
|
||||
crop->exp->set_expanded(true);
|
||||
|
Reference in New Issue
Block a user