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);
|
//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) {
|
gboolean giveMeAGo(void* data) {
|
||||||
|
@@ -19,13 +19,19 @@
|
|||||||
#ifndef __GUI_UTILS_
|
#ifndef __GUI_UTILS_
|
||||||
#define __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 <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);
|
Glib::ustring escapeHtmlChars(const Glib::ustring &src);
|
||||||
bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference = true);
|
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);
|
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
|
// 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.
|
// 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.
|
// 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 ()
|
Resize::~Resize ()
|
||||||
{
|
{
|
||||||
|
idle_register.destroy();
|
||||||
delete scale;
|
delete scale;
|
||||||
delete sizeBox;
|
delete sizeBox;
|
||||||
}
|
}
|
||||||
@@ -352,68 +352,76 @@ void Resize::sizeChanged (int mw, int mh, int ow, int oh)
|
|||||||
|
|
||||||
void Resize::setDimensions ()
|
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;
|
int refw, refh;
|
||||||
|
|
||||||
wconn.block (true);
|
if (self->appliesTo->get_active_row_number() == 0 && self->cropw) {
|
||||||
hconn.block (true);
|
|
||||||
scale->block(true);
|
|
||||||
|
|
||||||
if (appliesTo->get_active_row_number() == 0 && cropw) {
|
|
||||||
// Applies to Cropped area
|
// Applies to Cropped area
|
||||||
refw = cropw;
|
refw = self->cropw;
|
||||||
refh = croph;
|
refh = self->croph;
|
||||||
} else {
|
} else {
|
||||||
// Applies to Full image or crop is disabled
|
// Applies to Full image or crop is disabled
|
||||||
refw = maxw;
|
refw = self->maxw;
|
||||||
refh = maxh;
|
refh = self->maxh;
|
||||||
}
|
}
|
||||||
|
|
||||||
GThreadLock lock;
|
self->w->set_range(32, 4 * refw);
|
||||||
w->set_range (32, 4 * refw);
|
self->h->set_range(32, 4 * refh);
|
||||||
h->set_range (32, 4 * refh);
|
|
||||||
|
|
||||||
double tmpScale;
|
switch (self->spec->get_active_row_number()) {
|
||||||
|
case 0: {
|
||||||
switch (spec->get_active_row_number()) {
|
// Scale mode
|
||||||
case (0): // Scale mode
|
self->w->set_value(static_cast<double>(static_cast<int>(static_cast<double>(refw) * self->scale->getValue() + 0.5)));
|
||||||
w->set_value((double)((int)( (double)(refw) * scale->getValue() + 0.5) ));
|
self->h->set_value(static_cast<double>(static_cast<int>(static_cast<double>(refh) * self->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);
|
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
scale->block(false);
|
case 2: {
|
||||||
wconn.block (false);
|
// Height mode
|
||||||
hconn.block (false);
|
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()
|
void Resize::fitBoxScale()
|
||||||
|
@@ -25,25 +25,13 @@
|
|||||||
#include "toolpanel.h"
|
#include "toolpanel.h"
|
||||||
#include "guiutils.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:
|
public:
|
||||||
|
|
||||||
Resize ();
|
Resize ();
|
||||||
~Resize ();
|
~Resize ();
|
||||||
|
|
||||||
@@ -75,6 +63,20 @@ private:
|
|||||||
int getComputedHeight ();
|
int getComputedHeight ();
|
||||||
void notifyBBox ();
|
void notifyBBox ();
|
||||||
void updateGUI ();
|
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
|
#endif
|
||||||
|
Reference in New Issue
Block a user