Add IdleRegister
to deal with destruction while idle func is queued
This adds a little helper class to `guiutils.*` that unregisters in-flight idle functions queued by `IdleRegister::add()`. It's best to call `IdleRegister::destroy()` in the destructor of the class owning the `IdleRegister` instance. Otherwise make sure, it is the last member which will be deleted first. `Resize` now makes use of this new facility in `setDimensions()`, which also fixes #3673.
This commit is contained in:
@@ -43,6 +43,53 @@ guint add_idle (GSourceFunc function, gpointer data)
|
||||
//gtk_main_iteration_do(false);
|
||||
}
|
||||
|
||||
IdleRegister::~IdleRegister()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void IdleRegister::add(GSourceFunc function, gpointer data)
|
||||
{
|
||||
struct DataWrapper {
|
||||
IdleRegister* const self;
|
||||
GSourceFunc function;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
const auto dispatch = [](gpointer data) -> gboolean {
|
||||
DataWrapper* const data_wrapper = static_cast<DataWrapper*>(data);
|
||||
|
||||
if (!data_wrapper->function(data_wrapper->data)) {
|
||||
data_wrapper->self->mutex.lock();
|
||||
data_wrapper->self->ids.erase(data_wrapper);
|
||||
data_wrapper->self->mutex.unlock();
|
||||
|
||||
delete data_wrapper;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
DataWrapper* const data_wrapper = new DataWrapper{
|
||||
this,
|
||||
function,
|
||||
data
|
||||
};
|
||||
|
||||
mutex.lock();
|
||||
ids[data_wrapper] = add_idle(dispatch, data_wrapper);
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void IdleRegister::destroy()
|
||||
{
|
||||
mutex.lock();
|
||||
for (const auto id : ids) {
|
||||
g_source_remove(id.second);
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
gboolean giveMeAGo(void* data) {
|
||||
|
@@ -19,13 +19,19 @@
|
||||
#ifndef __GUI_UTILS_
|
||||
#define __GUI_UTILS_
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include <cairomm/cairomm.h>
|
||||
#include "../rtengine/rtengine.h"
|
||||
#include "../rtengine/coord.h"
|
||||
#include "rtimage.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include <gtkmm.h>
|
||||
|
||||
#include <cairomm/cairomm.h>
|
||||
|
||||
#include "../rtengine/coord.h"
|
||||
#include "../rtengine/noncopyable.h"
|
||||
#include "../rtengine/rtengine.h"
|
||||
|
||||
#include "rtimage.h"
|
||||
|
||||
Glib::ustring escapeHtmlChars(const Glib::ustring &src);
|
||||
bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference = true);
|
||||
@@ -40,6 +46,20 @@ void setExpandAlignProperties(Gtk::Widget *widget, bool hExpand, bool vExpand, e
|
||||
|
||||
guint add_idle (GSourceFunc function, gpointer data);
|
||||
|
||||
class IdleRegister final :
|
||||
public rtengine::NonCopyable
|
||||
{
|
||||
public:
|
||||
~IdleRegister();
|
||||
|
||||
void add(GSourceFunc function, gpointer data);
|
||||
void destroy();
|
||||
|
||||
private:
|
||||
std::map<void*, guint> ids;
|
||||
MyMutex mutex;
|
||||
};
|
||||
|
||||
// TODO: The documentation says gdk_threads_enter and gdk_threads_leave should be replaced
|
||||
// by g_main_context_invoke(), g_idle_add() and related functions, but this will require more extensive changes.
|
||||
// We silence those warnings until then so that we notice the others.
|
||||
|
104
rtgui/resize.cc
104
rtgui/resize.cc
@@ -118,7 +118,7 @@ Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), fals
|
||||
|
||||
Resize::~Resize ()
|
||||
{
|
||||
|
||||
idle_register.destroy();
|
||||
delete scale;
|
||||
delete sizeBox;
|
||||
}
|
||||
@@ -352,68 +352,76 @@ void Resize::sizeChanged (int mw, int mh, int ow, int oh)
|
||||
|
||||
void Resize::setDimensions ()
|
||||
{
|
||||
const auto func = [](gpointer data) -> gboolean {
|
||||
Resize* const self = static_cast<Resize*>(data);
|
||||
|
||||
self->wconn.block(true);
|
||||
self->hconn.block(true);
|
||||
self->scale->block(true);
|
||||
|
||||
int refw, refh;
|
||||
|
||||
wconn.block (true);
|
||||
hconn.block (true);
|
||||
scale->block(true);
|
||||
|
||||
if (appliesTo->get_active_row_number() == 0 && cropw) {
|
||||
if (self->appliesTo->get_active_row_number() == 0 && self->cropw) {
|
||||
// Applies to Cropped area
|
||||
refw = cropw;
|
||||
refh = croph;
|
||||
refw = self->cropw;
|
||||
refh = self->croph;
|
||||
} else {
|
||||
// Applies to Full image or crop is disabled
|
||||
refw = maxw;
|
||||
refh = maxh;
|
||||
refw = self->maxw;
|
||||
refh = self->maxh;
|
||||
}
|
||||
|
||||
GThreadLock lock;
|
||||
w->set_range (32, 4 * refw);
|
||||
h->set_range (32, 4 * refh);
|
||||
self->w->set_range(32, 4 * refw);
|
||||
self->h->set_range(32, 4 * refh);
|
||||
|
||||
double tmpScale;
|
||||
|
||||
switch (spec->get_active_row_number()) {
|
||||
case (0): // Scale mode
|
||||
w->set_value((double)((int)( (double)(refw) * scale->getValue() + 0.5) ));
|
||||
h->set_value((double)((int)( (double)(refh) * scale->getValue() + 0.5) ));
|
||||
break;
|
||||
|
||||
case (1): // Width mode
|
||||
tmpScale = w->get_value() / (double)refw;
|
||||
scale->setValue (tmpScale);
|
||||
h->set_value((double)((int)( (double)(refh) * tmpScale + 0.5) ));
|
||||
break;
|
||||
|
||||
case (2): // Height mode
|
||||
tmpScale = h->get_value() / (double)refh;
|
||||
scale->setValue (tmpScale);
|
||||
w->set_value((double)((int)( (double)(refw) * tmpScale + 0.5) ));
|
||||
break;
|
||||
|
||||
case (3): { // Bounding box mode
|
||||
double wSliderValue = w->get_value();
|
||||
double hSliderValue = h->get_value();
|
||||
|
||||
if ( (wSliderValue / hSliderValue) < ((double)refw / (double)refh)) {
|
||||
tmpScale = wSliderValue / (double)refw;
|
||||
} else {
|
||||
tmpScale = hSliderValue / (double)refh;
|
||||
}
|
||||
|
||||
scale->setValue (tmpScale);
|
||||
switch (self->spec->get_active_row_number()) {
|
||||
case 0: {
|
||||
// Scale mode
|
||||
self->w->set_value(static_cast<double>(static_cast<int>(static_cast<double>(refw) * self->scale->getValue() + 0.5)));
|
||||
self->h->set_value(static_cast<double>(static_cast<int>(static_cast<double>(refh) * self->scale->getValue() + 0.5)));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
case 1: {
|
||||
// Width mode
|
||||
const double tmp_scale = self->w->get_value() / static_cast<double>(refw);
|
||||
self->scale->setValue(tmp_scale);
|
||||
self->h->set_value(static_cast<double>(static_cast<int>(static_cast<double>(refh) * tmp_scale + 0.5)));
|
||||
break;
|
||||
}
|
||||
|
||||
scale->block(false);
|
||||
wconn.block (false);
|
||||
hconn.block (false);
|
||||
case 2: {
|
||||
// Height mode
|
||||
const double tmp_scale = self->h->get_value() / static_cast<double>(refh);
|
||||
self->scale->setValue(tmp_scale);
|
||||
self->w->set_value(static_cast<double>(static_cast<int>(static_cast<double>(refw) * tmp_scale + 0.5)));
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
// Bounding box mode
|
||||
const double tmp_scale =
|
||||
self->w->get_value() / self->h->get_value() < static_cast<double>(refw) / static_cast<double>(refh)
|
||||
? self->w->get_value() / static_cast<double>(refw)
|
||||
: self->h->get_value() / static_cast<double>(refh);
|
||||
|
||||
self->scale->setValue(tmp_scale);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self->scale->block(false);
|
||||
self->wconn.block(false);
|
||||
self->hconn.block(false);
|
||||
|
||||
return FALSE;
|
||||
};
|
||||
|
||||
idle_register.add(func, this);
|
||||
}
|
||||
|
||||
void Resize::fitBoxScale()
|
||||
|
@@ -25,25 +25,13 @@
|
||||
#include "toolpanel.h"
|
||||
#include "guiutils.h"
|
||||
|
||||
class Resize : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::SizeListener
|
||||
class Resize final :
|
||||
public ToolParamBlock,
|
||||
public AdjusterListener,
|
||||
public FoldableToolPanel,
|
||||
public rtengine::SizeListener
|
||||
{
|
||||
|
||||
protected:
|
||||
Adjuster* scale;
|
||||
Gtk::VBox* sizeBox;
|
||||
MyComboBoxText* appliesTo;
|
||||
MyComboBoxText* method;
|
||||
MyComboBoxText* spec;
|
||||
MySpinButton* w;
|
||||
MySpinButton* h;
|
||||
int maxw, maxh;
|
||||
int cropw, croph;
|
||||
sigc::connection sconn, aconn, wconn, hconn;
|
||||
bool wDirty, hDirty;
|
||||
ToolParamBlock* packBox;
|
||||
|
||||
public:
|
||||
|
||||
Resize ();
|
||||
~Resize ();
|
||||
|
||||
@@ -75,6 +63,20 @@ private:
|
||||
int getComputedHeight ();
|
||||
void notifyBBox ();
|
||||
void updateGUI ();
|
||||
|
||||
Adjuster* scale;
|
||||
Gtk::VBox* sizeBox;
|
||||
MyComboBoxText* appliesTo;
|
||||
MyComboBoxText* method;
|
||||
MyComboBoxText* spec;
|
||||
MySpinButton* w;
|
||||
MySpinButton* h;
|
||||
int maxw, maxh;
|
||||
int cropw, croph;
|
||||
sigc::connection sconn, aconn, wconn, hconn;
|
||||
bool wDirty, hDirty;
|
||||
ToolParamBlock* packBox;
|
||||
IdleRegister idle_register;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user