}
-namespace {
-
-class ShowMessage
- : public boost::signals2::trackable {
-public:
- ShowMessage(Buffer const & b) : buffer_(b) {}
- void operator()(docstring const & msg) const { buffer_.message(msg); }
-private:
- Buffer const & buffer_;
-};
-
-}
-
-
bool Converters::runLaTeX(Buffer const & buffer, string const & command,
OutputParams const & runparams, ErrorList & errorList)
{
buffer.filePath(), buffer.layoutPos(),
buffer.lastPreviewError());
TeXErrors terr;
- ShowMessage show(buffer);
- latex.message.connect(show);
+ // The connection closes itself at the end of the scope when latex is
+ // destroyed. One cannot close (and destroy) buffer while the converter is
+ // running.
+ latex.message.connect([&buffer](docstring const & msg){
+ buffer.message(msg);
+ });
int const result = latex.run(terr);
if (result & LaTeX::ERRORS)
#include "support/docstring.h"
#include "support/FileName.h"
-
-#include <boost/signals2.hpp>
+#include "support/signals.h"
#include <vector>
#include <set>
};
/// This signal emits an informative message
- boost::signals2::signal<void(docstring)> message;
+ signals2::signal<void(docstring)> message;
/**
#include "support/lassert.h"
#include "support/lstrings.h"
#include "support/os.h"
-
-#include "support/bind.h"
+#include "support/signals.h"
#include <iostream>
}
if (!write) {
- theApp()->registerSocketCallback(fd,
- bind(&LyXComm::read_ready, this));
+ // Make sure not to call read_ready after destruction.
+ weak_ptr<void> tracker = tracker_.p();
+ theApp()->registerSocketCallback(fd, [=](){
+ if (!tracker.expired())
+ read_ready();
+ });
}
return fd;
#ifndef SERVER_H
#define SERVER_H
-#include <boost/signals2/trackable.hpp>
+#include "support/signals.h"
#include <vector>
class Server;
-/** This class managed the pipes used for communicating with clients.
+/** This class manages the pipes used for communicating with clients.
Usage: Initialize with pipe-filename-base, client class to receive
messages, and callback-function that will be called with the messages.
When you want to send, use "send()".
a clean string interface.
*/
#ifndef _WIN32
-class LyXComm : public boost::signals2::trackable {
+class LyXComm {
#else
class LyXComm : public QObject {
Q_OBJECT
/// Did we defer loading of files to another instance?
bool deferred_loading_;
+
+ /// Track object's liveness
+ support::Trackable tracker_;
};
// Start autosave timer
if (lyxrc.autosave) {
- d.autosave_timeout_.timeout.connect(bind(&GuiView::autoSave, this));
+ // The connection is closed when this is destroyed.
+ d.autosave_timeout_.timeout.connect([this](){ autoSave();});
d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
d.autosave_timeout_.start();
}
d->setCursorShape(Qt::IBeamCursor);
- d->synthetic_mouse_event_.timeout.timeout.connect(
- bind(&GuiWorkArea::generateSyntheticMouseEvent,
- this));
+ // This connection is closed at the same time as this is destroyed.
+ d->synthetic_mouse_event_.timeout.timeout.connect([this](){
+ generateSyntheticMouseEvent();
+ });
// Initialize the vertical Scroll Bar
QObject::connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
#include "support/lassert.h"
#include "support/unique_ptr.h"
-#include "support/bind.h"
#include "support/TempFile.h"
using namespace std;
namespace graphics {
-class CacheItem::Impl : public boost::signals2::trackable {
+class CacheItem::Impl {
public:
///
/**
* If no file conversion is needed, then tryDisplayFormat() calls
* loadImage() directly.
- * \return true if a conversion is necessary and no error occurred.
+ * \return true if a conversion is necessary and no error occurred.
*/
bool tryDisplayFormat(FileName & filename, string & from);
ImageStatus status_;
/// This signal is emitted when the image loading status changes.
- boost::signals2::signal<void()> statusChanged;
-
- /// The connection of the signal ConvProcess::finishedConversion,
- boost::signals2::connection cc_;
+ signals2::signal<void()> statusChanged;
///
unique_ptr<Converter> converter_;
}
-boost::signals2::connection CacheItem::connect(slot_type const & slot) const
+signals2::connection CacheItem::connect(slot_type const & slot) const
{
return pimpl_->statusChanged.connect(slot);
}
if (monitor_)
return;
monitor_ = FileSystemWatcher::activeMonitor(filename_);
+ // Disconnected at the same time as this is destroyed.
monitor_->connect([=](){ startLoading(); });
}
status_ = WaitingToLoad;
- if (cc_.connected())
- cc_.disconnect();
-
if (converter_)
converter_.reset();
}
file_to_load_ = converter_ ? FileName(converter_->convertedFile())
: FileName();
converter_.reset();
- cc_.disconnect();
success = !file_to_load_.empty() && file_to_load_.isReadableFile();
// Connect a signal to this->imageConverted and pass this signal to
// the graphics converter so that we can load the modified file
// on completion of the conversion process.
- converter_ = make_unique<Converter>(doc_file_, filename, to_file_base.absFileName(),
+ converter_ = make_unique<Converter>(doc_file_, filename,
+ to_file_base.absFileName(),
from, to_);
- converter_->connect(bind(&Impl::imageConverted, this, _1));
+ // Connection is closed at the same time as *this is destroyed.
+ converter_->connect([this](bool success){
+ imageConverted(success);
+ });
converter_->startConversion();
}
#include "GraphicsTypes.h"
-#include <boost/signals2.hpp>
+#include "support/signals.h"
namespace lyx {
/** Connect and you'll be informed when the loading status of the image
* changes.
*/
- typedef boost::signals2::signal<void()>::slot_type slot_type;
+ typedef signals2::signal<void()>::slot_type slot_type;
///
- boost::signals2::connection connect(slot_type const &) const;
+ signals2::connection connect(slot_type const &) const;
private:
/// noncopyable
#include "support/lstrings.h"
#include "support/os.h"
-#include "support/bind.h"
#include "support/TempFile.h"
#include <sstream>
namespace graphics {
-class Converter::Impl : public boost::signals2::trackable {
+class Converter::Impl {
public:
///
- Impl(FileName const &, FileName const &, string const &, string const &, string const &);
+ Impl(FileName const & doc_fname,
+ FileName const & from_file, string const & to_file_base,
+ string const & from_format, string const & to_format);
///
void startConversion();
/** At the end of the conversion process inform the outside world
* by emitting a signal.
*/
- typedef boost::signals2::signal<void(bool)> SignalType;
+ typedef signals2::signal<void(bool)> sig;
///
- SignalType finishedConversion;
+ sig finishedConversion;
///
FileName const doc_fname_;
bool valid_process_;
///
bool finished_;
+ ///
+ Trackable tracker_;
};
Converter::Converter(FileName const & doc_fname,
- FileName const & from_file, string const & to_file_base,
- string const & from_format, string const & to_format)
+ FileName const & from_file, string const & to_file_base,
+ string const & from_format, string const & to_format)
: pimpl_(new Impl(doc_fname, from_file, to_file_base, from_format, to_format))
{}
}
-boost::signals2::connection Converter::connect(slot_type const & slot) const
+signals2::connection Converter::connect(slot_type const & slot) const
{
return pimpl_->finishedConversion.connect(slot);
}
return;
}
- ForkedCall::SignalTypePtr ptr =
- ForkedCallQueue::add(script_command_);
- ptr->connect(bind(&Impl::converted, this, _1, _2));
+ ForkedCall::sigPtr ptr = ForkedCallQueue::add(script_command_);
+ ptr->connect(ForkedCall::slot([this](pid_t pid, int retval){
+ converted(pid, retval);
+ }).track_foreign(tracker_.p()));
}
#ifndef GRAPHICSCONVERTER_H
#define GRAPHICSCONVERTER_H
-#include <boost/signals2.hpp>
+#include "support/signals.h"
+
namespace lyx {
/** Connect and you'll be informed when the conversion process has
* finished.
* If the conversion is successful, then the listener is passed \c true.
+ * The connection is closed when this is destroyed.
*/
- typedef boost::signals2::signal<void(bool)> sig_type;
+ typedef signals2::signal<void(bool)> sig_type;
typedef sig_type::slot_type slot_type;
///
- boost::signals2::connection connect(slot_type const &) const;
+ signals2::connection connect(slot_type const &) const;
/** If the conversion is successful, this returns the name of the
* resulting file.
LoaderQueue::LoaderQueue() : timer(s_millisecs_, Timeout::ONETIME),
- running_(false)
+ running_(false)
{
- timer.timeout.connect(bind(&LoaderQueue::loadNext, this));
+ // Disconnected when this is destroyed
+ timer.timeout.connect([this](){ loadNext(); });
}
void LoaderQueue::startLoader()
{
LYXERR(Debug::GRAPHICS, "LoaderQueue: waking up");
- running_ = true ;
+ running_ = true;
timer.setTimeout(s_millisecs_);
timer.start();
}
typedef std::shared_ptr<Image> ImagePtr;
-class Loader::Impl : public boost::signals2::trackable {
+class Loader::Impl {
friend class Loader;
public:
///
/// We modify a local copy of the image once it is loaded.
ImagePtr image_;
/// This signal is emitted when the image loading status changes.
- boost::signals2::signal<void()> signal_;
- /// The connection of the signal StatusChanged
- boost::signals2::connection sc_;
+ signals2::signal<void()> signal_;
+ /// The connection of the signal statusChanged
+ signals2::scoped_connection connection_;
double displayPixelRatio() const
{
}
-boost::signals2::connection Loader::connect(slot_type const & slot) const
+signals2::connection Loader::connect(slot const & slot) const
{
return pimpl_->signal_.connect(slot);
}
// signal needs to be disconnected.
try {
// This can in theory throw a BufferException
- sc_.disconnect();
+ connection_.disconnect();
} catch (...) {
LYXERR(Debug::GRAPHICS, "Unable to disconnect signal.");
}
if (continue_monitoring && !cached_item_->monitoring())
cached_item_->startMonitoring();
- sc_ = cached_item_->connect(bind(&Impl::statusChanged, this));
+ // This is a scoped connection
+ connection_ = cached_item_->connect([this](){ statusChanged(); });
}
#include "GraphicsTypes.h"
-#include <boost/signals2.hpp>
+#include "support/signals.h"
namespace lyx {
*/
void startLoading() const;
- /** Tries to reload the image.
+ /** Tries to reload the image.
*/
void reload() const;
/** Connect and you'll be informed when the loading status of the image
* changes.
*/
- typedef boost::signals2::signal<void()> sig_type;
- typedef sig_type::slot_type slot_type;
+ typedef signals2::signal<void()> sig;
+ typedef sig::slot_type slot;
///
- boost::signals2::connection connect(slot_type const &) const;
+ signals2::connection connect(slot const &) const;
/** The loaded image with Pixmap set.
* If the Pixmap is not yet set (see status() for why...), returns 0.
#include "support/FileName.h"
-#include "support/bind.h"
using namespace std;
using namespace lyx::support;
namespace lyx {
namespace graphics {
-class PreviewImage::Impl : public boost::signals2::trackable {
+class PreviewImage::Impl {
public:
///
Impl(PreviewImage & p, PreviewLoader & l,
}
-PreviewImage::Impl::Impl(PreviewImage & p, PreviewLoader & l,
- string const & s,
- FileName const & bf,
- double af)
+PreviewImage::Impl::Impl(PreviewImage & p, PreviewLoader & l, string const & s,
+ FileName const & bf, double af)
: parent_(p), ploader_(l), iloader_(l.buffer().fileName(), bf),
snippet_(s), ascent_frac_(af)
{
iloader_.setDisplayPixelRatio(l.displayPixelRatio());
- iloader_.connect(bind(&Impl::statusChanged, this));
+ // This connection is destroyed at the same time as this.
+ iloader_.connect([this](){ statusChanged(); });
}
#include "support/ForkedCalls.h"
#include "support/lstrings.h"
-#include "support/bind.h"
#include "support/TempFile.h"
#include <atomic>
namespace lyx {
namespace graphics {
-class PreviewLoader::Impl : public boost::signals2::trackable {
+class PreviewLoader::Impl {
public:
///
Impl(PreviewLoader & p, Buffer const & b);
void refreshPreviews();
/// Emit this signal when an image is ready for display.
- boost::signals2::signal<void(PreviewImage const &)> imageReady;
+ signals2::signal<void(PreviewImage const &)> imageReady;
Buffer const & buffer() const { return buffer_; }
/// We don't own this
static lyx::Converter const * pconverter_;
+
+ signals2::scoped_connection connection_;
};
}
-boost::signals2::connection PreviewLoader::connect(slot_type const & slot) const
+signals2::connection PreviewLoader::connect(slot const & slot) const
{
return pimpl_->imageReady.connect(slot);
}
<< " " << quoteName(latexfile.toFilesystemEncoding())
<< " --dpi " << font_scaling_factor_;
- // FIXME XHTML
+ // FIXME XHTML
// The colors should be customizable.
if (!buffer_.isExporting()) {
ColorCode const fg = PreviewLoader::foregroundColor();
ColorCode const bg = PreviewLoader::backgroundColor();
- cs << " --fg " << theApp()->hexName(fg)
+ cs << " --fg " << theApp()->hexName(fg)
<< " --bg " << theApp()->hexName(bg);
}
}
// Initiate the conversion from LaTeX to bitmap images files.
- ForkedCall::SignalTypePtr
- convert_ptr(new ForkedCall::SignalType);
- convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2));
+ ForkedCall::sigPtr convert_ptr = make_shared<ForkedCall::sig>();
+ // This is a scoped connection
+ connection_ = convert_ptr->connect([this](pid_t pid, int retval){
+ finishedGenerating(pid, retval);
+ });
ForkedCall call(buffer_.filePath());
int ret = call.startScript(command, convert_ptr);
#ifndef PREVIEWLOADER_H
#define PREVIEWLOADER_H
-#include <boost/signals2.hpp>
+#include "support/signals.h"
+
#include <QObject>
#include "ColorCode.h"
* has been created and is ready for loading through
* lyx::graphics::PreviewImage::image().
*/
- typedef boost::signals2::signal<void(PreviewImage const &)> sig_type;
- typedef sig_type::slot_type slot_type;
+ typedef signals2::signal<void(PreviewImage const &)> sig;
+ typedef sig::slot_type slot;
///
- boost::signals2::connection connect(slot_type const &) const;
+ signals2::connection connect(slot const &) const;
/** When PreviewImage has finished loading the image file into memory,
* it tells the PreviewLoader to tell the outside world
#include "graphics/PreviewLoader.h"
-#include "support/bind.h"
#include "support/convert.h"
#include "support/debug.h"
#include "support/ExceptionMessage.h"
// Mouse hover is not copied and remains empty
InsetExternal::InsetExternal(InsetExternal const & other)
: Inset(other),
- boost::signals2::trackable(),
params_(other.params_),
renderer_(other.renderer_->clone(this))
{}
case PREVIEW_INSTANT: {
renderer_ = make_unique<RenderMonitoredPreview>(this);
RenderMonitoredPreview * preview_ptr = renderer_->asMonitoredPreview();
+ // This connection is closed at the same time as this is destroyed.
preview_ptr->connect([=]() { fileChanged(); });
add_preview_and_start_loading(*preview_ptr, *this, buffer());
break;
#include "support/FileName.h"
#include "support/unique_ptr.h"
-#include <boost/signals2/trackable.hpp>
-
namespace lyx {
class RenderBase;
///
-class InsetExternal : public Inset, public boost::signals2::trackable
+class InsetExternal : public Inset
{
// Disable assignment operator, since it is not used, and it is too
// complicated to implement it consistently with the copy constructor
#include "support/lassert.h"
#include "support/lstrings.h"
-#include "support/bind.h"
-
using namespace std;
using namespace lyx::support;
RenderPreview::RenderPreview(RenderPreview const & other,
Inset const * inset)
: RenderBase(other),
- boost::signals2::trackable(),
snippet_(other.snippet_),
parent_(inset)
{}
-RenderPreview::~RenderPreview()
-{
- if (ploader_connection_.connected())
- ploader_connection_.disconnect();
-}
-
-
RenderBase * RenderPreview::clone(Inset const * inset) const
{
return new RenderPreview(*this, inset);
// If this is the first time of calling, connect to the
// PreviewLoader signal that'll inform us when the preview image
// is ready for loading.
- if (!ploader_connection_.connected()) {
- ploader_connection_ = ploader.connect(
- bind(&RenderPreview::imageReady, this, _1));
- }
+ if (!ploader_connection_.connected())
+ // This is a scoped connection.
+ ploader_connection_ =
+ ploader.connect([this](graphics::PreviewImage const & pi){
+ imageReady(pi);
+ });
ploader.add(snippet_);
}
}
-boost::signals2::connection
-RenderMonitoredPreview::connect(ChangedSig::slot_type const & slot)
+signals2::connection RenderMonitoredPreview::connect(slot const & slot)
{
return changed_.connect(slot);
}
#include "support/docstring.h"
#include "support/FileMonitor.h"
#include "support/FileName.h"
+#include "support/signals.h"
-#include <boost/signals2.hpp>
-#include <boost/signals2/trackable.hpp>
-#include <boost/signals2/connection.hpp>
namespace lyx {
} // namespace graphics
-class RenderPreview : public RenderBase, public boost::signals2::trackable {
+class RenderPreview : public RenderBase {
public:
/// Return true if preview is enabled in text (from LyXRC::preview)
static bool previewText();
RenderPreview(Inset const *);
RenderPreview(RenderPreview const &, Inset const *);
- ~RenderPreview();
RenderBase * clone(Inset const *) const;
/// Compute the size of the object, returned in dim
/** Store the connection to the preview loader so that we connect
* only once.
*/
- boost::signals2::connection ploader_connection_;
+ signals2::scoped_connection ploader_connection_;
/// Inform the core that the inset has changed.
Inset const * parent_;
void stopMonitoring() const;
/// Connect and you'll be informed when the file changes.
- typedef boost::signals2::signal<void()> ChangedSig;
- boost::signals2::connection connect(ChangedSig::slot_type const &);
+ /// Do not forget to track objects used by the slot.
+ typedef signals2::signal<void()> sig;
+ typedef sig::slot_type slot;
+ signals2::connection connect(slot const & slot);
/// equivalent to dynamic_cast
virtual RenderMonitoredPreview * asMonitoredPreview() { return this; }
private:
/// This signal is emitted if the file is modified
- ChangedSig changed_;
+ sig changed_;
///
mutable support::ActiveFileMonitorPtr monitor_;
///
}
-boost::signals2::connection
-FileMonitor::connect(sig::slot_type const & slot)
+signals2::connection FileMonitor::connect(slot const & slot)
{
return fileChanged_.connect(slot);
}
#define FILEMONITOR_H
#include "support/FileName.h"
+#include "support/signals.h"
#include <memory>
#include <QObject>
#include <QPointer>
-#include <boost/signals2.hpp>
-
namespace lyx {
namespace support {
public:
FileMonitor(std::shared_ptr<FileMonitorGuard> monitor);
- typedef boost::signals2::signal<void()> sig;
+ typedef signals2::signal<void()> sig;
+ typedef sig::slot_type slot;
/// Connect and you'll be informed when the file has changed.
- boost::signals2::connection connect(sig::slot_type const &);
+ signals2::connection connect(slot const &);
/// disconnect all slots connected to the boost signal fileChanged_ or to
/// the qt signal fileChanged()
void disconnect();
//
/////////////////////////////////////////////////////////////////////
-class Murder : public boost::signals2::trackable {
+class Murder {
public:
//
static void killItDead(int secs, pid_t pid)
Murder(int secs, pid_t pid)
: timeout_(1000*secs, Timeout::ONETIME), pid_(pid)
{
- timeout_.timeout.connect(lyx::bind(&Murder::kill, this));
+ // Connection is closed with this.
+ timeout_.timeout.connect([this](){ kill(); });
timeout_.start();
}
int ForkedCall::startScript(Starttype wait, string const & what)
{
if (wait != Wait) {
- retval_ = startScript(what, SignalTypePtr());
+ retval_ = startScript(what, sigPtr());
return retval_;
}
}
-int ForkedCall::startScript(string const & what, SignalTypePtr signal)
+int ForkedCall::startScript(string const & what, sigPtr signal)
{
command_ = commandPrep(trim(what));
signal_ = signal;
namespace ForkedCallQueue {
/// A process in the queue
-typedef pair<string, ForkedCall::SignalTypePtr> Process;
+typedef pair<string, ForkedCall::sigPtr> Process;
/** Add a process to the queue. Processes are forked sequentially
* only one is running at a time.
* Connect to the returned signal and you'll be informed when
* the process has ended.
*/
-ForkedCall::SignalTypePtr add(string const & process);
+ForkedCall::sigPtr add(string const & process);
/// in-progress queue
static queue<Process> callQueue_;
///
void callback(pid_t, int);
-ForkedCall::SignalTypePtr add(string const & process)
+ForkedCall::sigPtr add(string const & process)
{
- ForkedCall::SignalTypePtr ptr;
- ptr.reset(new ForkedCall::SignalType);
+ ForkedCall::sigPtr ptr;
+ ptr.reset(new ForkedCall::sig);
callQueue_.push(Process(process, ptr));
if (!running_)
startCaller();
#ifndef FORKEDCALLS_H
#define FORKEDCALLS_H
+#include "support/signals.h"
#include "support/strfwd.h"
-#include <boost/signals2.hpp>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
///
virtual std::shared_ptr<ForkedProcess> clone() const = 0;
- /** A SignalType signal can be emitted once the forked process
+ /** A Signal signal can be emitted once the forked process
* has finished. It passes:
* the PID of the child and;
* the return value from the child.
* we can return easily to C++ methods, rather than just globally
* accessible functions.
*/
- typedef boost::signals2::signal<void(pid_t, int)> SignalType;
+ typedef signals2::signal<void(pid_t, int)> sig;
+ typedef sig::slot_type slot;
/** The signal is connected in the calling routine to the desired
* slot. We pass a shared_ptr rather than a reference to the signal
* class (and hence the signal) to be destructed before the forked
* call is complete.
*
- * It doesn't matter if the slot disappears, SigC takes care of that.
+ * Use Slot::track or Signal::scoped_connection to ensure that the
+ * connection is closed before the slot expires.
*/
- typedef std::shared_ptr<SignalType> SignalTypePtr;
+ typedef std::shared_ptr<sig> sigPtr;
/** Invoking the following methods makes sense only if the command
* is running asynchronously!
pid_t fork();
/// Callback function
- SignalTypePtr signal_;
+ sigPtr signal_;
/// identifying command (for display in the GUI perhaps).
std::string command_;
};
-/**
+/**
* An instance of class ForkedCall represents a single child process.
*
* Class ForkedCall uses fork() and execvp() to lauch the child process.
int startScript(Starttype, std::string const & what);
///
- int startScript(std::string const & what, SignalTypePtr);
+ int startScript(std::string const & what, sigPtr ptr);
private:
///
namespace ForkedCallQueue {
-ForkedCall::SignalTypePtr add(std::string const & process);
+ForkedCall::sigPtr add(std::string const & process);
/// Query whether the queue is running a forked process now.
bool running();
qstring_helpers.h \
regex.h \
RefChanger.h \
+ signals.h \
socktools.cpp \
socktools.h \
strfwd.h \
#ifndef TIMEOUT_H
#define TIMEOUT_H
-#include <boost/signals2.hpp>
+#include "support/signals.h"
namespace lyx {
/// restart the timer
void restart();
/// signal emitted on timer expiry
- boost::signals2::signal<void()> timeout;
+ signals2::signal<void()> timeout;
/// emit the signal
void emit();
/// set the timer type
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file signals.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Guillaume Munch
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef LYX_SIGNALS_H
+#define LYX_SIGNALS_H
+
+#include "boost/signals2.hpp"
+
+#include <memory>
+
+namespace lyx {
+
+namespace signals2 = ::boost::signals2;
+
+namespace support {
+
+/// A small utility to use with signals2::slot_type::track_foreign when the
+/// parent object is not handled by a shared_ptr, or to track the lifetime of an
+/// object. Using Trackable to track lifetimes is less thread-safe than tracking
+/// their parents directly with a shared_ptr as recommended by signals2, but it
+/// makes it easier for transitioning old code. (Essentially because Trackable
+/// will not prevent the deletion of the parent by a concurrent thread.)
+class Trackable {
+public:
+ Trackable() : p_(std::make_shared<int>(0)) {}
+ Trackable(Trackable const &) : Trackable() {}
+ Trackable(Trackable &&) : Trackable() {}
+ Trackable & operator=(Trackable const &) { return *this; }
+ Trackable & operator=(Trackable &&) { return *this; }
+ // This weak pointer lets you know if the parent object has been destroyed
+ std::weak_ptr<void> p() const { return p_; }
+private:
+ std::shared_ptr<void> const p_;
+};
+
+} // namespace support
+
+} // namespace lyx
+
+
+#endif