diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc index 6228cb1c7..8f9885b50 100644 --- a/rtgui/crophandler.cc +++ b/rtgui/crophandler.cc @@ -29,19 +29,35 @@ using namespace rtengine; -CropHandler::CropHandler () - : zoom(100), ww(0), wh(0), cax(-1), cay(-1), - cx(0), cy(0), cw(0), ch(0), cropX(0), cropY(0), cropW(0), cropH(0), enabled(false), - cropimg(nullptr), cropimgtrue(nullptr), cropimg_width(0), cropimg_height(0), - cix(0), ciy(0), ciw(0), cih(0), cis(1), - initial(false), isLowUpdatePriority(false), ipc(nullptr), crop(nullptr), - displayHandler(nullptr) +CropHandler::CropHandler() : + zoom(100), + ww(0), + wh(0), + cax(-1), + cay(-1), + cx(0), + cy(0), + cw(0), + ch(0), + cropX(0), + cropY(0), + cropW(0), + cropH(0), + enabled(false), + cropimg_width(0), + cropimg_height(0), + cix(0), + ciy(0), + ciw(0), + cih(0), + cis(1), + isLowUpdatePriority(false), + ipc(nullptr), + crop(nullptr), + displayHandler(nullptr), + redraw_needed(false), + initial(false) { - - idle_helper = new IdleHelper; - idle_helper->destroyed = false; - idle_helper->pending = 0; - idle_helper->cropHandler = this; } CropHandler::~CropHandler () @@ -59,16 +75,6 @@ CropHandler::~CropHandler () delete crop; // will do the same than destroy, plus delete the object crop = nullptr; } - - cimg.lock (); - - if (idle_helper->pending) { - idle_helper->destroyed = true; - } else { - delete idle_helper; - } - - cimg.unlock (); } void CropHandler::setEditSubscriber (EditSubscriber* newSubscriber) @@ -308,110 +314,94 @@ void CropHandler::setDetailedCrop (IImage8* im, IImage8* imtrue, rtengine::procp cropPixbuf.clear (); - if (cropimg) { - delete [] cropimg; + if (!cropimg.empty()) { + cropimg.clear(); } - cropimg = nullptr; - - if (cropimgtrue) { - delete [] cropimgtrue; + if (!cropimgtrue.empty()) { + cropimgtrue.clear(); } - cropimgtrue = nullptr; - if (ax == cropX && ay == cropY && aw == cropW && ah == cropH && askip == (zoom >= 1000 ? 1 : zoom / 10)) { 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]; - memcpy (cropimg, im->getData(), 3 * cropimg_width * cropimg_height); - memcpy (cropimgtrue, imtrue->getData(), 3 * cropimg_width * cropimg_height); + const std::size_t cropimg_size = 3 * cropimg_width * cropimg_height; + cropimg.assign(im->getData(), im->getData() + cropimg_size); + cropimgtrue.assign(imtrue->getData(), imtrue->getData() + cropimg_size); cix = ax; ciy = ay; ciw = aw; cih = ah; cis = askip; - idle_helper->pending++; - const auto func = [](gpointer data) -> gboolean { - IdleHelper* const idle_helper = static_cast(data); + bool expected = false; - if (idle_helper->destroyed) { - if (idle_helper->pending == 1) { - delete idle_helper; + if (redraw_needed.compare_exchange_strong(expected, true)) { + const auto func = [](gpointer data) -> gboolean { + CropHandler* const self = static_cast(data); + + self->cimg.lock (); + + if (self->redraw_needed.exchange(false)) { + self->cropPixbuf.clear (); + + if (!self->enabled) { + self->cropimg.clear(); + self->cropimgtrue.clear(); + self->cimg.unlock (); + return FALSE; + } + + if (!self->cropimg.empty()) { + if (self->cix == self->cropX && self->ciy == self->cropY && self->ciw == self->cropW && self->cih == self->cropH && self->cis == (self->zoom >= 1000 ? 1 : self->zoom / 10)) { + // calculate final image size + float czoom = self->zoom >= 1000 ? + self->zoom / 1000.f : + float((self->zoom/10) * 10) / float(self->zoom); + int imw = self->cropimg_width * czoom; + int imh = self->cropimg_height * czoom; + + if (imw > self->ww) { + imw = self->ww; + } + + if (imh > self->wh) { + imh = self->wh; + } + + Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (self->cropimg.data(), Gdk::COLORSPACE_RGB, false, 8, self->cropimg_width, self->cropimg_height, 3 * self->cropimg_width); + self->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); + tmpPixbuf->scale (self->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom, czoom, Gdk::INTERP_TILES); + tmpPixbuf.clear (); + + Glib::RefPtr tmpPixbuftrue = Gdk::Pixbuf::create_from_data (self->cropimgtrue.data(), Gdk::COLORSPACE_RGB, false, 8, self->cropimg_width, self->cropimg_height, 3 * self->cropimg_width); + self->cropPixbuftrue = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); + tmpPixbuftrue->scale (self->cropPixbuftrue, 0, 0, imw, imh, 0, 0, czoom, czoom, Gdk::INTERP_TILES); + tmpPixbuftrue.clear (); + } + + self->cropimg.clear(); + self->cropimgtrue.clear(); + } + + self->cimg.unlock (); + + if (self->displayHandler) { + self->displayHandler->cropImageUpdated (); + + if (self->initial.exchange(false)) { + self->displayHandler->initialImageArrived (); + } + } } else { - idle_helper->pending--; + self->cimg.unlock(); } return FALSE; - } + }; - CropHandler* ch = idle_helper->cropHandler; - - ch->cimg.lock (); - ch->cropPixbuf.clear (); - - if (!ch->enabled) { - delete [] ch->cropimg; - ch->cropimg = nullptr; - delete [] ch->cropimgtrue; - ch->cropimgtrue = nullptr; - ch->cimg.unlock (); - return FALSE; - } - - 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 / 10)) { - // calculate final image size - float czoom = ch->zoom >= 1000 ? - ch->zoom / 1000.f : - float((ch->zoom/10) * 10) / float(ch->zoom); - int imw = ch->cropimg_width * czoom; - int imh = ch->cropimg_height * czoom; - - if (imw > ch->ww) { - imw = ch->ww; - } - - if (imh > ch->wh) { - imh = ch->wh; - } - - Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (ch->cropimg, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, ch->cropimg_height, 3 * ch->cropimg_width); - ch->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); - tmpPixbuf->scale (ch->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom, czoom, Gdk::INTERP_TILES); - tmpPixbuf.clear (); - - Glib::RefPtr tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 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, czoom, Gdk::INTERP_TILES); - tmpPixbuftrue.clear (); - } - - delete [] ch->cropimg; - ch->cropimg = nullptr; - delete [] ch->cropimgtrue; - ch->cropimgtrue = nullptr; - } - - ch->cimg.unlock (); - - if (ch->displayHandler) { - ch->displayHandler->cropImageUpdated (); - - if (ch->initial) { - ch->displayHandler->initialImageArrived (); - ch->initial = false; - } - } - - idle_helper->pending--; - - return FALSE; - }; - - idle_register.add(func, idle_helper, G_PRIORITY_HIGH_IDLE); + idle_register.add(func, this/*, G_PRIORITY_HIGH_IDLE*/); + } } cimg.unlock (); @@ -468,13 +458,11 @@ void CropHandler::setEnabled (bool e) crop->setListener (nullptr); } - cimg.lock (); - delete [] cropimg; - cropimg = nullptr; - delete [] cropimgtrue; - cropimgtrue = nullptr; - cropPixbuf.clear (); - cimg.unlock (); + cimg.lock(); + cropimg.clear(); + cropimgtrue.clear(); + cropPixbuf.clear(); + cimg.unlock(); } else { update (); } diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index 1e7a9202b..17f2ca47d 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -19,11 +19,16 @@ #ifndef __CROPHANDLER__ #define __CROPHANDLER__ +#include +#include + +#include + #include "../rtengine/rtengine.h" -#include "threadutils.h" + #include "edit.h" #include "lockablecolorpicker.h" -#include +#include "threadutils.h" class CropDisplayHandler { @@ -98,12 +103,6 @@ public: MyMutex cimg; private: - struct IdleHelper { - CropHandler* cropHandler; - bool destroyed; - int pending; - }; - void compDim (); int zoom; // scale factor (e.g. 5 if 1:5 scale) ; if 1:1 scale and bigger, factor is multiplied by 1000 (i.e. 1000 for 1:1 scale, 2000 for 2:1, etc...) @@ -112,17 +111,18 @@ private: int cx, cy, cw, ch; // position and size of the requested crop ; position expressed in image coordinates, so cx and cy might be negative and cw and ch higher than the image's 1:1 size int cropX, cropY, cropW, cropH; // cropPixbuf's displayed area (position and size), i.e. coordinates in 1:1 scale, i.e. cx, cy, cw & ch trimmed to the image's bounds bool enabled; - unsigned char* cropimg; - unsigned char* cropimgtrue; + std::vector cropimg; + std::vector cropimgtrue; int cropimg_width, cropimg_height, cix, ciy, ciw, cih, cis; - bool initial; bool isLowUpdatePriority; rtengine::StagedImageProcessor* ipc; rtengine::DetailedCrop* crop; CropDisplayHandler* displayHandler; - IdleHelper* idle_helper; + + std::atomic redraw_needed; + std::atomic initial; IdleRegister idle_register; }; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index e9cb3ea43..00582942c 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -253,6 +253,7 @@ void ToolPanelCoordinator::addPanel (Gtk::Box* where, FoldableToolPanel* panel, ToolPanelCoordinator::~ToolPanelCoordinator () { + idle_register.destroy(); closeImage (); @@ -262,29 +263,58 @@ ToolPanelCoordinator::~ToolPanelCoordinator () void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans) { - GThreadLock lock; - if (isRaw) { - rawPanelSW->set_sensitive (true); - if (isBayer) { - sensorxtrans->FoldableToolPanel::hide(); - sensorbayer->FoldableToolPanel::show(); - preprocess->FoldableToolPanel::show(); - flatfield->FoldableToolPanel::show(); - } else if (isXtrans) { - sensorxtrans->FoldableToolPanel::show(); - sensorbayer->FoldableToolPanel::hide(); - preprocess->FoldableToolPanel::show(); - flatfield->FoldableToolPanel::show(); - } else { - sensorbayer->FoldableToolPanel::hide(); - sensorxtrans->FoldableToolPanel::hide(); - preprocess->FoldableToolPanel::hide(); - flatfield->FoldableToolPanel::hide(); + const auto func = [](gpointer data) -> gboolean { + ToolPanelCoordinator* const self = static_cast(data); + + self->rawPanelSW->set_sensitive (true); + self->sensorxtrans->FoldableToolPanel::hide(); + self->sensorbayer->FoldableToolPanel::show(); + self->preprocess->FoldableToolPanel::show(); + self->flatfield->FoldableToolPanel::show(); + + return FALSE; + }; + idle_register.add(func, this); + } + else if (isXtrans) { + const auto func = [](gpointer data) -> gboolean { + ToolPanelCoordinator* const self = static_cast(data); + + self->rawPanelSW->set_sensitive (true); + self->sensorxtrans->FoldableToolPanel::show(); + self->sensorbayer->FoldableToolPanel::hide(); + self->preprocess->FoldableToolPanel::show(); + self->flatfield->FoldableToolPanel::show(); + + return FALSE; + }; + idle_register.add(func, this); + } + else { + const auto func = [](gpointer data) -> gboolean { + ToolPanelCoordinator* const self = static_cast(data); + + self->rawPanelSW->set_sensitive (true); + self->sensorbayer->FoldableToolPanel::hide(); + self->sensorxtrans->FoldableToolPanel::hide(); + self->preprocess->FoldableToolPanel::hide(); + self->flatfield->FoldableToolPanel::hide(); + + return FALSE; + }; + idle_register.add(func, this); } } else { - rawPanelSW->set_sensitive (false); + const auto func = [](gpointer data) -> gboolean { + ToolPanelCoordinator* const self = static_cast(data); + + self->rawPanelSW->set_sensitive (false); + + return FALSE; + }; + idle_register.add(func, this); } } diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index c6d2e6380..b387ac988 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -301,6 +301,9 @@ public: void editModeSwitchedOff (); void setEditProvider (EditDataProvider *provider); + +private: + IdleRegister idle_register; }; #endif