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:
Flössie
2017-02-09 20:25:58 +01:00
parent 281982f329
commit 824ecaed41
4 changed files with 155 additions and 78 deletions

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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()

View File

@@ -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