Please, note that your patch is incomplete for autotools. Attached you
can find a complementary patch that allows configuration and compilation
with autotools.
The hunks for 3rdparty/Makefile.am and 3rdparty/nod/Makefile.am should
replace yours, while all other hunks are to be added to your patch.
In my cursory test your patch seems to work well.
--
Enrico
Thanks for testing and autotools support, Enrico!
I've updated the patch with your changes.
Yuriy
From 8819f5c3bd9fca014c46412ec63d7ea98509a5b7 Mon Sep 17 00:00:00 2001
From: Yuriy Skalko <yuriy.ska...@gmail.com>
Date: Sun, 13 Dec 2020 20:13:16 +0200
Subject: [PATCH] Use new signal library `nod` instead of `boost::signals2`
Thanks Enrico for updating autotools files.
---
3rdparty/Makefile.am | 8 +-
3rdparty/nod/Makefile.am | 4 +
3rdparty/nod/README.md | 257 +++++++++++
3rdparty/nod/nod.hpp | 680 +++++++++++++++++++++++++++++
CMakeLists.txt | 2 +
config/lyxinclude.m4 | 28 ++
configure.ac | 2 +
src/Makefile.am | 2 +-
src/Server.cpp | 8 +-
src/client/Makefile.am | 2 +-
src/frontends/Makefile.am | 2 +-
src/frontends/qt/Makefile.am | 2 +-
src/graphics/GraphicsConverter.cpp | 27 +-
src/graphics/GraphicsConverter.h | 6 +-
src/graphics/GraphicsLoader.cpp | 1 +
src/graphics/PreviewLoader.cpp | 19 +-
src/graphics/PreviewLoader.h | 7 +-
src/support/ForkedCalls.cpp | 2 +
src/support/Makefile.am | 2 +-
src/support/signals.h | 4 +-
src/tex2lyx/Makefile.am | 2 +-
21 files changed, 1020 insertions(+), 47 deletions(-)
create mode 100644 3rdparty/nod/Makefile.am
create mode 100644 3rdparty/nod/README.md
create mode 100644 3rdparty/nod/nod.hpp
diff --git a/3rdparty/Makefile.am b/3rdparty/Makefile.am
index ec12adb883..7b5c569f32 100644
--- a/3rdparty/Makefile.am
+++ b/3rdparty/Makefile.am
@@ -1,6 +1,10 @@
include $(top_srcdir)/config/common.am
-DIST_SUBDIRS = boost dtl hunspell mythes libiconv zlib
+DIST_SUBDIRS = boost dtl hunspell mythes libiconv zlib nod
+
+if USE_INCLUDED_NOD
+NOD = nod
+endif
if USE_INCLUDED_BOOST
BOOST = boost
@@ -26,7 +30,7 @@ if BUILD_INCLUDED_DTL
DTL=dtl
endif
-SUBDIRS = $(BOOST) $(DTL) $(HUNSPELL) $(MYTHES) $(ICONV) $(ZLIB)
+SUBDIRS = $(BOOST) $(DTL) $(HUNSPELL) $(MYTHES) $(ICONV) $(ZLIB) $(NOD)
EXTRA_DIST = \
scripts/evince_sync/evince_backward_search \
diff --git a/3rdparty/nod/Makefile.am b/3rdparty/nod/Makefile.am
new file mode 100644
index 0000000000..07caaa47fb
--- /dev/null
+++ b/3rdparty/nod/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/config/common.am
+
+EXTRA_DIST = nod \
+ README.md
diff --git a/3rdparty/nod/README.md b/3rdparty/nod/README.md
new file mode 100644
index 0000000000..0cf74f1d4f
--- /dev/null
+++ b/3rdparty/nod/README.md
@@ -0,0 +1,257 @@
+# Nod
+[](https://travis-ci.org/fr00b0/nod)
+[](https://github.com/fr00b0/nod/releases)
+
+Dependency free, header only signals and slot library implemented with C++11.
+
+## Usage
+
+### Simple usage
+The following example creates a signal and then connects a lambda as a slot.
+
+```cpp
+// Create a signal which accepts slots with no arguments and void return value.
+nod::signal<void()> signal;
+// Connect a lambda slot that writes "Hello, World!" to stdout
+signal.connect([](){
+ std::cout << "Hello, World!" << std::endl;
+ });
+// Call the slots
+signal();
+```
+
+### Connecting multiple slots
+If multiple slots are connected to the same signal, all of the slots will be
+called when the signal is invoked. The slots will be called in the same order
+as they where connected.
+
+```cpp
+void endline() {
+ std::cout << std::endl;
+}
+
+// Create a signal
+nod::signal<void()> signal;
+// Connect a lambda that prints a message
+signal.connect([](){
+ std::cout << "Message without endline!";
+ });
+// Connect a function that prints a endline
+signal.connect(endline);
+
+// Call the slots
+signal();
+```
+
+#### Slot type
+The signal types in the library support connection of the same types that is
+supported by `std::function<T>`.
+
+### Slot arguments
+When a signal calls it's connected slots, any arguments passed to the signal
+are propagated to the slots. To make this work, we do need to specify the
+signature of the signal to accept the arguments.
+
+```cpp
+void print_sum( int x, int y ) {
+ std::cout << x << "+" << y << "=" << (x+y) << std::endl;
+}
+void print_product( int x, int y ) {
+ std::cout << x << "*" << y << "=" << (x*y) << std::endl;
+}
+
+
+// We create a signal with two integer arguments.
+nod::signal<void(int,int)> signal;
+// Let's connect our slot
+signal.connect( print_sum );
+signal.connect( print_product );
+
+// Call the slots
+signal(10, 15);
+signal(-5, 7);
+
+```
+
+### Disconnecting slots
+There are many circumstances where the programmer needs to diconnect a slot
that
+no longer want to recieve events from the signal. This can be really important
+if the lifetime of the slots are shorter than the lifetime of the signal. That
+could cause the signal to call slots that have been destroyed but not
+disconnected, leading to undefined behaviour and probably segmentation faults.
+
+When a slot is connected, the return value from the `connect` method returns
+an instance of the class `nod::connection`, that can be used to disconnect
+that slot.
+
+```cpp
+// Let's create a signal
+nod::signal<void()> signal;
+// Connect a slot, and save the connection
+nod::connection connection = signal.connect([](){
+ std::cout <<
"I'm connected!" << std::endl;
+ });
+// Triggering the signal will call the slot
+signal();
+// Now we disconnect the slot
+connection.disconnect();
+// Triggering the signal will no longer call the slot
+signal();
+```
+
+### Scoped connections
+To assist in disconnecting slots, one can use the class
`nod::scoped_connection`
+to capture a slot connection. A scoped connection will automatically disconnect
+the slot when the connection object goes out of scope.
+
+```cpp
+// We create a signal
+nod::signal<void()> signal;
+// Let's use a scope to control lifetime
+{
+ // Let's save the connection in a scoped_connection
+ nod::scoped_connection connection =
+ signal.connect([](){
+ std::cout << "This message should only be emitted
once!" << std::endl;
+ });
+ // If we trigger the signal, the slot will be called
+ signal();
+} // Our scoped connection is destructed, and disconnects the slot
+// Triggering the signal now will not call the slot
+signal();
+```
+
+### Slot return values
+
+#### Accumulation of return values
+It is possible for slots to have a return value. The return values can be
+returned from the signal using a *accumulator*, which is a function object that
+acts as a proxy object that processes the slot return values. When triggering a
+signal through a accumulator, the accumulator gets called for each slot return
+value, does the desired accumulation and then return the result to the code
+triggering the signal. The accumulator is designed to work in a similar way as
+the STL numerical algorithm `std::accumulate`.
+
+```cpp
+// We create a singal with slots that return a value
+nod::signal<int(int, int)> signal;
+// Then we connect some signals
+signal.connect( std::plus<int>{} );
+signal.connect( std::multiplies<int>{} );
+signal.connect( std::minus<int>{} );
+// Let's say we want to calculate the sum of all the slot return values
+// when triggering the singal with the parameters 10 and 100.
+// We do this by accumulating the return values with the initial value 0
+// and a plus function object, like so:
+std::cout << "Sum: " << signal.accumulate(0, std::plus<int>{})(10,100) <<
std::endl;
+// Or accumulate by multiplying (this needs 1 as initial value):
+std::cout << "Product: " << signal.accumulate(1,
std::multiplies<int>{})(10,100) << std::endl;
+// If we instead want to build a vector with all the return values
+// we can accumulate them this way (start with a empty vector and add each
value):
+auto vec = signal.accumulate( std::vector<int>{}, []( std::vector<int> result,
int value ) {
+ result.push_back( value );
+ return result;
+ })(10,100);
+
+std::cout << "Vector: ";
+for( auto const& element : vec ) {
+ std::cout << element << " ";
+}
+std::cout << std::endl;
+```
+#### Aggregation
+As we can see from the previous example, we can use the `accumulate` method if
+we want to aggregate all the return values of the slots. Doing the aggregation
+that way is not very optimal. It is both a inefficient algorithm for doing
+aggreagtion to a container, and it obscures the call site as the caller needs
to
+express the aggregation using the verb *accumulate*. To remedy these
+shortcomings we can turn to the method `aggregate` instead. This is a template
+method, taking the type of container to aggregate to as a template parameter.
+
+```cpp
+// We create a singal
+nod::signal<int(int, int)> signal;
+// Let's connect some slots
+signal.connect( std::plus<int>{} );
+signal.connect( std::multiplies<int>{} );
+signal.connect( std::minus<int>{} );
+// We can now trigger the signal and aggregate the slot return values
+auto vec = signal.aggregate<std::vector<int>>(10,100);
+
+std::cout << "Result: ";
+for( auto const& element : vec ) {
+ std::cout << element << " ";
+}
+std::cout << std::endl;
+```
+
+## Thread safety
+There are two types of signals in the library. The first is `nod::signal<T>`
+which is safe to use in a multi threaded environment. Multiple threads can
read,
+write, connect slots and disconnect slots simultaneously, and the signal will
+provide the nessesary synchronization. When triggering a slignal, all the
+registered slots will be called and executed by the thread that triggered the
+signal.
+
+The second type of signal is `nod::unsafe_signal<T>` which is **not** safe to
+use in a multi threaded environment. No syncronization will be performed on the
+internal state of the signal. Instances of the signal should theoretically be
+safe to read from multiple thread simultaneously, as long as no thread is
+writing to the same object at the same time. There can be a performance gain
+involved in using the unsafe version of a signal, since no syncronization
+primitives will be used.
+
+`nod::connection` and `nod::scoped_connection` are thread safe for reading from
+multiple threads, as long as no thread is writing to the same object. Writing
in
+this context means calling any non const member function, including destructing
+the object. If an object is being written by one thread, then all reads and
+writes to that object from the same or other threads needs to be prevented.
+This basically means that a connection is only allowed to be disconnected from
+one thread, and you should not check connection status or reassign the
+connection while it is being disconnected.
+
+## Building the tests
+The test project uses [premake5](https://premake.github.io/download.html) to
+generate make files or similiar.
+
+### Linux
+To build and run the tests using gcc and gmake on linux, execute the following
+from the test directory:
+```bash
+premake5 gmake
+make -C build/gmake
+bin/gmake/debug/nod_tests
+```
+
+### Visual Studio 2013
+To build and run the tests, execute the following from the test directory:
+
+```batchfile
+REM Adjust paths to suite your environment
+c:\path\to\premake\premake5.exe vs2013
+"c:\Program Files (x86)\Microsoft Visual Studio
12.0\Common7\Tools\vsvars32.bat"
+msbuild /m build\vs2013\nod_tests.sln
+bin\vs2013\debug\nod_tests.exe
+```
+
+## The MIT License (MIT)
+
+Copyright (c) 2015 Fredrik Berggren
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/3rdparty/nod/nod.hpp b/3rdparty/nod/nod.hpp
new file mode 100644
index 0000000000..5c4a93cb85
--- /dev/null
+++ b/3rdparty/nod/nod.hpp
@@ -0,0 +1,680 @@
+#ifndef IG_NOD_INCLUDE_NOD_HPP
+#define IG_NOD_INCLUDE_NOD_HPP
+
+#include <vector> // std::vector
+#include <functional> // std::function
+#include <mutex> // std::mutex, std::lock_guard
+#include <memory> // std::shared_ptr, std::weak_ptr
+#include <algorithm> // std::find_if()
+#include <cassert> // assert()
+#include <thread> // std::this_thread::yield()
+#include <type_traits> // std::is_same
+#include <iterator> // std::back_inserter
+
+namespace nod {
+ // implementational details
+ namespace detail {
+ /// Interface for type erasure when disconnecting slots
+ struct disconnector {
+ virtual void operator()( std::size_t index ) const = 0;
+ };
+ /// Deleter that doesn't delete
+ inline void no_delete(disconnector*){
+ };
+ } // namespace detail
+
+ /// Base template for the signal class
+ template <class P, class T>
+ class signal_type;
+
+
+ /// Connection class.
+ ///
+ /// This is used to be able to disconnect slots after they have been
connected.
+ /// Used as return type for the connect method of the signals.
+ ///
+ /// Connections are default constructible.
+ /// Connections are not copy constructible or copy assignable.
+ /// Connections are move constructible and move assignable.
+ ///
+ class connection {
+ public:
+ /// Default constructor
+ connection() :
+ _index()
+ {}
+
+ // Connection are not copy constructible or copy
assignable
+ connection( connection const& ) = delete;
+ connection& operator=( connection const& ) = delete;
+
+ /// Move constructor
+ /// @param other The instance to move from.
+ connection( connection&& other ) :
+ _weak_disconnector(
std::move(other._weak_disconnector) ),
+ _index( other._index )
+ {}
+
+ /// Move assign operator.
+ /// @param other The instance to move from.
+ connection& operator=( connection&& other ) {
+ _weak_disconnector = std::move(
other._weak_disconnector );
+ _index = other._index;
+ return *this;
+ }
+
+ /// @returns `true` if the connection is connected to a
signal object,
+ /// and `false` otherwise.
+ bool connected() const {
+ return !_weak_disconnector.expired();
+ }
+
+ /// Disconnect the slot from the connection.
+ ///
+ /// If the connection represents a slot that is
connected to a signal object, calling
+ /// this method will disconnect the slot from that
object. The result of this operation
+ /// is that the slot will stop receiving calls when the
signal is invoked.
+ void disconnect();
+
+ private:
+ /// The signal template is a friend of the connection,
since it is the
+ /// only one allowed to create instances using the
meaningful constructor.
+ template<class P,class T> friend class signal_type;
+
+ /// Create a connection.
+ /// @param shared_disconnector Disconnector instance
that will be used to disconnect
+ /// the connection when
the time comes. A weak pointer
+ /// to the disconnector
will be held within the connection
+ /// object.
+ /// @param index The slot index of the
connection.
+ connection( std::shared_ptr<detail::disconnector>
const& shared_disconnector, std::size_t index ) :
+ _weak_disconnector( shared_disconnector ),
+ _index( index )
+ {}
+
+ /// Weak pointer to the current disconnector functor.
+ std::weak_ptr<detail::disconnector> _weak_disconnector;
+ /// Slot index of the connected slot.
+ std::size_t _index;
+ };
+
+ /// Scoped connection class.
+ ///
+ /// This type of connection is automatically disconnected when
+ /// the connection object is destructed.
+ ///
+ class scoped_connection
+ {
+ public:
+ /// Scoped are default constructible
+ scoped_connection() = default;
+ /// Scoped connections are not copy constructible
+ scoped_connection( scoped_connection const& ) = delete;
+ /// Scoped connections are not copy assingable
+ scoped_connection& operator=( scoped_connection const&
) = delete;
+
+ /// Move constructor
+ scoped_connection( scoped_connection&& other ) :
+ _connection( std::move(other._connection) )
+ {}
+
+ /// Move assign operator.
+ /// @param other The instance to move from.
+ scoped_connection& operator=( scoped_connection&& other
) {
+ reset( std::move( other._connection ) );
+ return *this;
+ }
+
+ /// Construct a scoped connection from a connection
object
+ /// @param connection The connection object to manage
+ scoped_connection( connection&& c ) :
+ _connection( std::forward<connection>(c) )
+ {}
+
+ /// destructor
+ ~scoped_connection() {
+ disconnect();
+ }
+
+ /// Assignment operator moving a new connection into
the instance.
+ /// @note If the scoped_connection instance already
contains a
+ /// connection, that connection will be
disconnected as if
+ /// the scoped_connection was destroyed.
+ /// @param c New connection to manage
+ scoped_connection& operator=( connection&& c ) {
+ reset( std::forward<connection>(c) );
+ return *this;
+ }
+
+ /// Reset the underlying connection to another
connection.
+ /// @note The connection currently managed by the
scoped_connection
+ /// instance will be disconnected when resetting.
+ /// @param c New connection to manage
+ void reset( connection&& c = {} ) {
+ disconnect();
+ _connection = std::move(c);
+ }
+
+ /// Release the underlying connection, without
disconnecting it.
+ /// @returns The newly released connection instance is
returned.
+ connection release() {
+ connection c = std::move(_connection);
+ _connection = connection{};
+ return c;
+ }
+
+ ///
+ /// @returns `true` if the connection is connected to a
signal object,
+ /// and `false` otherwise.
+ bool connected() const {
+ return _connection.connected();
+ }
+
+ /// Disconnect the slot from the connection.
+ ///
+ /// If the connection represents a slot that is
connected to a signal object, calling
+ /// this method will disconnect the slot from that
object. The result of this operation
+ /// is that the slot will stop receiving calls when the
signal is invoked.
+ void disconnect() {
+ _connection.disconnect();
+ }
+
+ private:
+ /// Underlying connection object
+ connection _connection;
+ };
+
+ /// Policy for multi threaded use of signals.
+ ///
+ /// This policy provides mutex and lock types for use in
+ /// a multithreaded environment, where signals and slots
+ /// may exists in different threads.
+ ///
+ /// This policy is used in the `nod::signal` type provided
+ /// by the library.
+ struct multithread_policy
+ {
+ using mutex_type = std::mutex;
+ using mutex_lock_type = std::unique_lock<mutex_type>;
+ /// Function that yields the current thread, allowing
+ /// the OS to reschedule.
+ static void yield_thread() {
+ std::this_thread::yield();
+ }
+ /// Function that defers a lock to a lock function that
prevents deadlock
+ static mutex_lock_type defer_lock(mutex_type & m){
+ return mutex_lock_type{m, std::defer_lock};
+ }
+ /// Function that locks two mutexes and prevents deadlock
+ static void lock(mutex_lock_type & a,mutex_lock_type & b) {
+ std::lock(a,b);
+ }
+ };
+
+ /// Policy for single threaded use of signals.
+ ///
+ /// This policy provides dummy implementations for mutex
+ /// and lock types, resulting in that no synchronization
+ /// will take place.
+ ///
+ /// This policy is used in the `nod::unsafe_signal` type
+ /// provided by the library.
+ struct singlethread_policy
+ {
+ /// Dummy mutex type that doesn't do anything
+ struct mutex_type{};
+ /// Dummy lock type, that doesn't do any locking.
+ struct mutex_lock_type
+ {
+ /// A lock type must be constructible from a
+ /// mutex type from the same thread policy.
+ explicit mutex_lock_type( mutex_type const& ) {
+ }
+ };
+ /// Dummy implementation of thread yielding, that
+ /// doesn't do any actual yielding.
+ static void yield_thread() {
+ }
+ /// Dummy implemention of defer_lock that doesn't
+ /// do anything
+ static mutex_lock_type defer_lock(mutex_type &m){
+ return mutex_lock_type{m};
+ }
+ /// Dummy implemention of lock that doesn't
+ /// do anything
+ static void lock(mutex_lock_type &,mutex_lock_type &) {
+ }
+ };
+
+ /// Signal accumulator class template.
+ ///
+ /// This acts sort of as a proxy for triggering a signal and
+ /// accumulating the slot return values.
+ ///
+ /// This class is not really intended to instantiate by client code.
+ /// Instances are aquired as return values of the method `accumulate()`
+ /// called on signals.
+ ///
+ /// @tparam S Type of signal. The signal_accumulator acts
+ /// as a type of proxy for a signal instance of
+ /// this type.
+ /// @tparam T Type of initial value of the accumulate algorithm.
+ /// This type must meet the requirements of
`CopyAssignable`
+ /// and `CopyConstructible`
+ /// @tparam F Type of accumulation function.
+ /// @tparam A... Argument types of the underlying signal type.
+ ///
+ template <class S, class T, class F, class...A>
+ class signal_accumulator
+ {
+ public:
+ /// Result type when calling the accumulating function
operator.
+ using result_type = typename std::result_of<F(T,
typename S::slot_type::result_type)>::type;
+
+ /// Construct a signal_accumulator as a proxy to a
given signal
+ //
+ /// @param signal Signal instance.
+ /// @param init Initial value of the accumulate
algorithm.
+ /// @param func Binary operation function object
that will be
+ /// applied to all slot return values.
+ /// The signature of the function
should be
+ /// equivalent of the following:
+ /// `R func( T1 const& a, T2 const& b
)`
+ /// - The signature does not need to
have `const&`.
+ /// - The initial value, type `T`,
must be implicitly
+ /// convertible to `R`
+ /// - The return type `R` must be
implicitly convertible
+ /// to type `T1`.
+ /// - The type `R` must be
`CopyAssignable`.
+ /// - The type
`S::slot_type::result_type` (return type of
+ /// the signals slots) must be
implicitly convertible to
+ /// type `T2`.
+ signal_accumulator( S const& signal, T init, F func ) :
+ _signal( signal ),
+ _init( init ),
+ _func( func )
+ {}
+
+ /// Function call operator.
+ ///
+ /// Calling this will trigger the underlying signal and
accumulate
+ /// all of the connected slots return values with the
current
+ /// initial value and accumulator function.
+ ///
+ /// When called, this will invoke the accumulator
function will
+ /// be called for each return value of the slots. The
semantics
+ /// are similar to the `std::accumulate` algorithm.
+ ///
+ /// @param args Arguments to propagate to the slots
of the
+ /// underlying when triggering the signal.
+ result_type operator()( A const& ... args ) const {
+ return _signal.trigger_with_accumulator( _init,
_func, args... );
+ }
+
+ private:
+
+ /// Reference to the underlying signal to proxy.
+ S const& _signal;
+ /// Initial value of the accumulate algorithm.
+ T _init;
+ /// Accumulator function.
+ F _func;
+
+ };
+
+ /// Signal template specialization.
+ ///
+ /// This is the main signal implementation, and it is used to
+ /// implement the observer pattern whithout the overhead
+ /// boilerplate code that typically comes with it.
+ ///
+ /// Any function or function object is considered a slot, and
+ /// can be connected to a signal instance, as long as the signature
+ /// of the slot matches the signature of the signal.
+ ///
+ /// @tparam P Threading policy for the signal.
+ /// A threading policy must provide two type definitions:
+ /// - P::mutex_type, this type will be used as a mutex
+ /// in the signal_type class template.
+ /// - P::mutex_lock_type, this type must implement a
+ /// constructor that takes a P::mutex_type as a
parameter,
+ /// and it must have the semantics of a scoped mutex
lock
+ /// like std::lock_guard, i.e. locking in the
constructor
+ /// and unlocking in the destructor.
+ ///
+ /// @tparam R Return value type of the slots connected to the
signal.
+ /// @tparam A... Argument types of the slots connected to the signal.
+ template <class P, class R, class... A >
+ class signal_type<P,R(A...)>
+ {
+ public:
+ /// signals are not copy constructible
+ signal_type( signal_type const& ) = delete;
+ /// signals are not copy assignable
+ signal_type& operator=( signal_type const& ) = delete;
+ /// signals are move constructible
+ signal_type(signal_type&& other)
+ {
+ mutex_lock_type lock{other._mutex};
+ _slot_count = std::move(other._slot_count);
+ _slots = std::move(other._slots);
+ if(other._shared_disconnector != nullptr)
+ {
+ _disconnector = disconnector{ this };
+ _shared_disconnector =
std::move(other._shared_disconnector);
+ // replace the disconnector with our
own disconnector
+
*static_cast<disconnector*>(_shared_disconnector.get()) = _disconnector;
+ }
+ }
+ /// signals are move assignable
+ signal_type& operator=(signal_type&& other)
+ {
+ auto lock = thread_policy::defer_lock(_mutex);
+ auto other_lock =
thread_policy::defer_lock(other._mutex);
+ thread_policy::lock(lock,other_lock);
+
+ _slot_count = std::move(other._slot_count);
+ _slots = std::move(other._slots);
+ if(other._shared_disconnector != nullptr)
+ {
+ _disconnector = disconnector{ this };
+ _shared_disconnector =
std::move(other._shared_disconnector);
+ // replace the disconnector with our
own disconnector
+
*static_cast<disconnector*>(_shared_disconnector.get()) = _disconnector;
+ }
+ return *this;
+ }
+
+ /// signals are default constructible
+ signal_type() :
+ _slot_count(0)
+ {}
+
+ // Destruct the signal object.
+ ~signal_type() {
+ invalidate_disconnector();
+ }
+
+ /// Type that will be used to store the slots for this
signal type.
+ using slot_type = std::function<R(A...)>;
+ /// Type that is used for counting the slots connected
to this signal.
+ using size_type = typename
std::vector<slot_type>::size_type;
+
+
+ /// Connect a new slot to the signal.
+ ///
+ /// The connected slot will be called every time the
signal
+ /// is triggered.
+ /// @param slot The slot to connect. This must be a
callable with
+ /// the same signature as the signal
itself.
+ /// @return A connection object is returned, and
can be used to
+ /// disconnect the slot.
+ template <class T>
+ connection connect( T&& slot ) {
+ mutex_lock_type lock{ _mutex };
+ _slots.push_back( std::forward<T>(slot) );
+ std::size_t index = _slots.size()-1;
+ if( _shared_disconnector == nullptr ) {
+ _disconnector = disconnector{ this };
+ _shared_disconnector =
std::shared_ptr<detail::disconnector>{&_disconnector, detail::no_delete};
+ }
+ ++_slot_count;
+ return connection{ _shared_disconnector, index
};
+ }
+
+ /// Function call operator.
+ ///
+ /// Calling this is how the signal is triggered and the
+ /// connected slots are called.
+ ///
+ /// @note The slots will be called in the order they
were
+ /// connected to the signal.
+ ///
+ /// @param args Arguments that will be propagated to
the
+ /// connected slots when they are called.
+ void operator()( A const&... args ) const {
+ for( auto const& slot : copy_slots() ) {
+ if( slot ) {
+ slot( args... );
+ }
+ }
+ }
+
+ /// Construct a accumulator proxy object for the signal.
+ ///
+ /// The intended purpose of this function is to create
a function
+ /// object that can be used to trigger the signal and
accumulate
+ /// all the slot return values.
+ ///
+ /// The algorithm used to accumulate slot return values
is similar
+ /// to `std::accumulate`. A given binary function is
called for
+ /// each return value with the parameters consisting of
the
+ /// return value of the accumulator function applied to
the
+ /// previous slots return value, and the current slots
return value.
+ /// A initial value must be provided for the first slot
return type.
+ ///
+ /// @note This can only be used on signals that have
slots with
+ /// non-void return types, since we can't
accumulate void
+ /// values.
+ ///
+ /// @tparam T The type of the initial value given
to the accumulator.
+ /// @tparam F The accumulator function type.
+ /// @param init Initial value given to the
accumulator.
+ /// @param op Binary operator function object to
apply by the accumulator.
+ /// The signature of the function should
be
+ /// equivalent of the following:
+ /// `R func( T1 const& a, T2 const& b
)`
+ /// - The signature does not need to
have `const&`.
+ /// - The initial value, type `T`, must
be implicitly
+ /// convertible to `R`
+ /// - The return type `R` must be
implicitly convertible
+ /// to type `T1`.
+ /// - The type `R` must be
`CopyAssignable`.
+ /// - The type
`S::slot_type::result_type` (return type of
+ /// the signals slots) must be
implicitly convertible to
+ /// type `T2`.
+ template <class T, class F>
+ signal_accumulator<signal_type, T, F, A...> accumulate(
T init, F op ) const {
+ static_assert( std::is_same<R,void>::value ==
false, "Unable to accumulate slot return values with 'void' as return type." );
+ return { *this, init, op };
+ }
+
+
+ /// Trigger the signal, calling the slots and aggregate
all
+ /// the slot return values into a container.
+ ///
+ /// @tparam C The type of container. This type must
be
+ /// `DefaultConstructible`, and usable
with
+ /// `std::back_insert_iterator`.
Additionally it
+ /// must be either copyable or moveable.
+ /// @param args The arguments to propagate to the
slots.
+ template <class C>
+ C aggregate( A const&... args ) const {
+ static_assert( std::is_same<R,void>::value ==
false, "Unable to aggregate slot return values with 'void' as return type." );
+ C container;
+ auto iterator = std::back_inserter( container );
+ for( auto const& slot : copy_slots() ) {
+ if( slot ) {
+ (*iterator) = slot( args... );
+ }
+ }
+ return container;
+ }
+
+ /// Count the number of slots connected to this signal
+ /// @returns The number of connected slots
+ size_type slot_count() const {
+ return _slot_count;
+ }
+
+ /// Determine if the signal is empty, i.e. no slots are
connected
+ /// to it.
+ /// @returns `true` is returned if the signal has no
connected
+ /// slots, and `false` otherwise.
+ bool empty() const {
+ return slot_count() == 0;
+ }
+
+ /// Disconnects all slots
+ /// @note This operation invalidates all
scoped_connection objects
+ void disconnect_all_slots() {
+ mutex_lock_type lock{ _mutex };
+ _slots.clear();
+ _slot_count = 0;
+ invalidate_disconnector();
+ }
+
+ private:
+ template<class, class, class, class...> friend class
signal_accumulator;
+ /// Thread policy currently in use
+ using thread_policy = P;
+ /// Type of mutex, provided by threading policy
+ using mutex_type = typename thread_policy::mutex_type;
+ /// Type of mutex lock, provided by threading policy
+ using mutex_lock_type = typename
thread_policy::mutex_lock_type;
+
+ /// Invalidate the internal disconnector object in a way
+ /// that is safe according to the current thread policy.
+ ///
+ /// This will effectively make all current connection
objects to
+ /// to this signal incapable of disconnecting, since
they keep a
+ /// weak pointer to the shared disconnector object.
+ void invalidate_disconnector() {
+ // If we are unlucky, some of the connected
slots
+ // might be in the process of disconnecting
from other threads.
+ // If this happens, we are risking to destruct
the disconnector
+ // object managed by our shared pointer before
they are done
+ // disconnecting. This would be bad. To solve
this problem, we
+ // discard the shared pointer (that is pointing
to the disconnector
+ // object within our own instance), but keep a
weak pointer to that
+ // instance. We then stall the destruction
until all other weak
+ // pointers have released their "lock"
(indicated by the fact that
+ // we will get a nullptr when locking our weak
pointer).
+ std::weak_ptr<detail::disconnector>
weak{_shared_disconnector};
+ _shared_disconnector.reset();
+ while( weak.lock() != nullptr ) {
+ // we just yield here, allowing the OS
to reschedule. We do
+ // this until all threads has released
the disconnector object.
+ thread_policy::yield_thread();
+ }
+ }
+
+ /// Retrieve a copy of the current slots
+ ///
+ /// It's useful and necessary to copy the slots so we
don't need
+ /// to hold the lock while calling the slots. If we
hold the lock
+ /// we prevent the called slots from modifying the
slots vector.
+ /// This simple "double buffering" will allow slots to
disconnect
+ /// themself or other slots and connect new slots.
+ std::vector<slot_type> copy_slots() const
+ {
+ mutex_lock_type lock{ _mutex };
+ return _slots;
+ }
+
+ /// Implementation of the signal accumulator function
call
+ template <class T, class F>
+ typename signal_accumulator<signal_type, T, F,
A...>::result_type trigger_with_accumulator( T value, F& func, A const&... args
) const {
+ for( auto const& slot : copy_slots() ) {
+ if( slot ) {
+ value = func( value, slot(
args... ) );
+ }
+ }
+ return value;
+ }
+
+ /// Implementation of the disconnection operation.
+ ///
+ /// This is private, and only called by the connection
+ /// objects created when connecting slots to this
signal.
+ /// @param index The slot index of the slot that
should
+ /// be disconnected.
+ void disconnect( std::size_t index ) {
+ mutex_lock_type lock( _mutex );
+ assert( _slots.size() > index );
+ if( _slots[ index ] != nullptr ) {
+ --_slot_count;
+ }
+ _slots[ index ] = slot_type{};
+ while( _slots.size()>0 && !_slots.back() ) {
+ _slots.pop_back();
+ }
+ }
+
+ /// Implementation of the shared disconnection state
+ /// used by all connection created by signal instances.
+ ///
+ /// This inherits the @ref detail::disconnector
interface
+ /// for type erasure.
+ struct disconnector :
+ detail::disconnector
+ {
+ /// Default constructor, resulting in a no-op
disconnector.
+ disconnector() :
+ _ptr(nullptr)
+ {}
+
+ /// Create a disconnector that works with a
given signal instance.
+ /// @param ptr Pointer to the signal instance
that the disconnector
+ /// should work with.
+ disconnector( signal_type<P,R(A...)>* ptr ) :
+ _ptr( ptr )
+ {}
+
+ /// Disconnect a given slot on the current
signal instance.
+ /// @note If the instance is default
constructed, or created
+ /// with `nullptr` as signal pointer this
operation will
+ /// effectively be a no-op.
+ /// @param index The index of the slot to
disconnect.
+ void operator()( std::size_t index ) const
override {
+ if( _ptr ) {
+ _ptr->disconnect( index );
+ }
+ }
+
+ /// Pointer to the current signal.
+ signal_type<P,R(A...)>* _ptr;
+ };
+
+ /// Mutex to synchronize access to the slot vector
+ mutable mutex_type _mutex;
+ /// Vector of all connected slots
+ std::vector<slot_type> _slots;
+ /// Number of connected slots
+ size_type _slot_count;
+ /// Disconnector operation, used for executing
disconnection in a
+ /// type erased manner.
+ disconnector _disconnector;
+ /// Shared pointer to the disconnector. All connection
objects has a
+ /// weak pointer to this pointer for performing
disconnections.
+ std::shared_ptr<detail::disconnector>
_shared_disconnector;
+ };
+
+ // Implementation of the disconnect operation of the connection class
+ inline void connection::disconnect() {
+ auto ptr = _weak_disconnector.lock();
+ if( ptr ) {
+ (*ptr)( _index );
+ }
+ _weak_disconnector.reset();
+ }
+
+ /// Signal type that is safe to use in multithreaded environments,
+ /// where the signal and slots exists in different threads.
+ /// The multithreaded policy provides mutexes and locks to synchronize
+ /// access to the signals internals.
+ ///
+ /// This is the recommended signal type, even for single threaded
+ /// environments.
+ template <class T> using signal = signal_type<multithread_policy, T>;
+
+ /// Signal type that is unsafe in multithreaded environments.
+ /// No synchronizations are provided to the signal_type for accessing
+ /// the internals.
+ ///
+ /// Only use this signal type if you are sure that your environment is
+ /// single threaded and performance is of importance.
+ template <class T> using unsafe_signal =
signal_type<singlethread_policy, T>;
+} // namespace nod
+
+#endif // IG_NOD_INCLUDE_NOD_HPP
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1805a9c6b8..015fcc31b7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -940,6 +940,8 @@ set(Lyx_Boost_Libraries)
add_definitions(-DBOOST_USER_CONFIG=<config.h>)
include_directories(${TOP_SRC_DIR}/3rdparty/boost)
+include_directories(${TOP_SRC_DIR}/3rdparty/nod)
+
if(WIN32)
if(LYX_CONSOLE)
set(LYX_QTMAIN_LIBRARY)
diff --git a/config/lyxinclude.m4 b/config/lyxinclude.m4
index d07e1bcfcc..0e9ff19b5b 100644
--- a/config/lyxinclude.m4
+++ b/config/lyxinclude.m4
@@ -416,6 +416,34 @@ if test x$GXX = xyes; then
fi
])
+dnl Usage: LYX_USE_INCLUDED_NOD : select if the included nod should be used.
+AC_DEFUN([LYX_USE_INCLUDED_NOD],[
+ AC_MSG_CHECKING([whether to use included nod library])
+ AC_ARG_WITH(included-nod,
+ [AS_HELP_STRING([--without-included-nod], [do not use the nod lib
supplied with LyX, try to find one in the system directories - compilation will
abort if nothing suitable is found])],
+ [lyx_cv_with_included_nod=$withval],
+ [lyx_cv_with_included_nod=yes])
+ AM_CONDITIONAL(USE_INCLUDED_NOD, test x$lyx_cv_with_included_nod = xyes)
+ AC_MSG_RESULT([$lyx_cv_with_included_nod])
+ if test x$lyx_cv_with_included_nod = xyes ; then
+ lyx_included_libs="$lyx_included_libs nod"
+ NOD_INCLUDES='-I$(top_srcdir)/3rdparty/nod'
+ else
+ NOD_INCLUDES=
+ AC_LANG_PUSH(C++)
+ AC_MSG_CHECKING([for nod library])
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([#include <nod.hpp>],
+ [nod::scoped_connection conn;])],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ AC_MSG_ERROR([cannot find suitable nod library (do not use
--without-included-nod)])
+ ])
+ AC_LANG_POP(C++)
+ fi
+ AC_SUBST(NOD_INCLUDES)
+])
+
dnl Usage: LYX_USE_INCLUDED_BOOST : select if the included boost should
dnl be used.
AC_DEFUN([LYX_USE_INCLUDED_BOOST],[
diff --git a/configure.ac b/configure.ac
index 318986b4e2..9853fa53da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -94,6 +94,7 @@ AC_SUBST(LIBPSAPI)
AC_CHECK_LIB(gdi32, main)
AC_CHECK_LIB(ole32, main)
+LYX_USE_INCLUDED_NOD
LYX_USE_INCLUDED_BOOST
### we need to know the byte order for unicode conversions
@@ -337,6 +338,7 @@ AC_CONFIG_FILES([Makefile \
3rdparty/dtl/Makefile \
3rdparty/hunspell/Makefile \
3rdparty/mythes/Makefile \
+ 3rdparty/nod/Makefile \
3rdparty/libiconv/Makefile \
$ICONV_ICONV_H_IN \
3rdparty/zlib/Makefile \
diff --git a/src/Makefile.am b/src/Makefile.am
index 032b174cf3..31701f2fb1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,7 +5,7 @@ include $(top_srcdir)/config/common.am
AM_CPPFLAGS += -I$(top_srcdir)/src
AM_CPPFLAGS += $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES)
AM_CPPFLAGS += $(ENCHANT_CFLAGS) $(HUNSPELL_CFLAGS) $(MYTHES_INCLUDES)
-AM_CPPFLAGS += $(QT_CPPFLAGS) $(QT_CORE_INCLUDES)
+AM_CPPFLAGS += $(NOD_INCLUDES) $(QT_CPPFLAGS) $(QT_CORE_INCLUDES)
if BUILD_CLIENT_SUBDIR
CLIENT = client
diff --git a/src/Server.cpp b/src/Server.cpp
index 79340492c6..8d9e0c61db 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -60,8 +60,12 @@
#include <iostream>
#ifdef _WIN32
-#include <io.h>
-#include <QCoreApplication>
+# include <io.h>
+# include <QCoreApplication>
+#else
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
#endif
#include <QThread>
diff --git a/src/client/Makefile.am b/src/client/Makefile.am
index 5a6db831af..580556d6b1 100644
--- a/src/client/Makefile.am
+++ b/src/client/Makefile.am
@@ -9,7 +9,7 @@ bin_PROGRAMS = lyxclient
EXTRA_DIST = lyxclient.1in CMakeLists.txt
AM_CPPFLAGS += -I$(srcdir)/.. \
- $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES)
+ $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES) $(NOD_INCLUDES)
lyxclient_LDADD = \
$(top_builddir)/src/support/liblyxsupport.a \
diff --git a/src/frontends/Makefile.am b/src/frontends/Makefile.am
index 2acdeebb26..a8f233e25a 100644
--- a/src/frontends/Makefile.am
+++ b/src/frontends/Makefile.am
@@ -7,7 +7,7 @@ DIST_SUBDIRS = qt .
noinst_LIBRARIES = liblyxfrontends.a
AM_CPPFLAGS += -I$(srcdir)/.. \
- $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES)
+ $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES) $(NOD_INCLUDES)
liblyxfrontends_a_SOURCES = \
alert.h \
diff --git a/src/frontends/qt/Makefile.am b/src/frontends/qt/Makefile.am
index 2a497af887..d559623310 100644
--- a/src/frontends/qt/Makefile.am
+++ b/src/frontends/qt/Makefile.am
@@ -37,7 +37,7 @@ AM_CPPFLAGS += \
-I$(top_srcdir)/src/frontends \
-I$(top_srcdir)/images \
$(QT_INCLUDES) \
- $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES)
+ $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES) $(NOD_INCLUDES)
SOURCEFILES = \
ButtonPolicy.cpp \
diff --git a/src/graphics/GraphicsConverter.cpp
b/src/graphics/GraphicsConverter.cpp
index 1461fdb27c..66e198ace4 100644
--- a/src/graphics/GraphicsConverter.cpp
+++ b/src/graphics/GraphicsConverter.cpp
@@ -38,7 +38,7 @@ namespace graphics {
class Converter::Impl {
public:
///
- Impl(FileName const & doc_fname,
+ Impl(Converter const & parent, FileName const & doc_fname,
FileName const & from_file, string const & to_file_base,
string const & from_format, string const & to_format);
@@ -59,6 +59,8 @@ public:
///
sig finishedConversion;
+ ///
+ Converter const & parent_;
///
FileName const doc_fname_;
///
@@ -71,8 +73,6 @@ public:
bool valid_process_;
///
bool finished_;
- ///
- Trackable tracker_;
};
@@ -86,16 +86,10 @@ bool Converter::isReachable(string const & from_format_name,
Converter::Converter(FileName const & doc_fname,
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))
+ : pimpl_(make_shared<Impl>(*this, doc_fname, from_file, to_file_base,
from_format, to_format))
{}
-Converter::~Converter()
-{
- delete pimpl_;
-}
-
-
void Converter::startConversion() const
{
pimpl_->startConversion();
@@ -123,10 +117,10 @@ static void build_script(string const & doc_fname,
ostream & script);
-Converter::Impl::Impl(FileName const & doc_fname,
+Converter::Impl::Impl(Converter const & parent, FileName const & doc_fname,
FileName const & from_file, string const & to_file_base,
string const & from_format, string const & to_format)
- : doc_fname_(doc_fname), valid_process_(false), finished_(false)
+ : parent_(parent), doc_fname_(doc_fname), valid_process_(false),
finished_(false)
{
LYXERR(Debug::GRAPHICS, "Converter c-tor:\n"
<< "doc_fname: " << doc_fname
@@ -188,9 +182,12 @@ void Converter::Impl::startConversion()
}
ForkedCall::sigPtr ptr = ForkedCallQueue::add(script_command_);
- ptr->connect(ForkedCall::slot([this](pid_t pid, int retval){
- converted(pid, retval);
- }).track_foreign(tracker_.p()));
+ weak_ptr<Converter::Impl> this_ = parent_.pimpl_;
+ ptr->connect([this_](pid_t pid, int retval){
+ if (auto p = this_.lock()) {
+ p->converted(pid, retval);
+ }
+ });
}
diff --git a/src/graphics/GraphicsConverter.h b/src/graphics/GraphicsConverter.h
index c038029bd8..7eb3689ad1 100644
--- a/src/graphics/GraphicsConverter.h
+++ b/src/graphics/GraphicsConverter.h
@@ -19,6 +19,7 @@
#include "support/signals.h"
+#include <memory>
namespace lyx {
@@ -39,9 +40,6 @@ public:
support::FileName const & from_file, std::string const &
to_file_base,
std::string const & from_format, std::string const &
to_format);
- /// Needed for the pimpl
- ~Converter();
-
/// We are explicit about when we begin the conversion process.
void startConversion() const;
@@ -70,7 +68,7 @@ private:
/// Use the Pimpl idiom to hide the internals.
class Impl;
/// The pointer never changes although *pimpl_'s contents may.
- Impl * const pimpl_;
+ std::shared_ptr<Impl> const pimpl_;
};
} // namespace graphics
diff --git a/src/graphics/GraphicsLoader.cpp b/src/graphics/GraphicsLoader.cpp
index f0a0934091..2316a4ac69 100644
--- a/src/graphics/GraphicsLoader.cpp
+++ b/src/graphics/GraphicsLoader.cpp
@@ -21,6 +21,7 @@
#include "support/lassert.h"
#include "support/Timeout.h"
+#include <list>
#include <queue>
#include <memory>
#include <set>
diff --git a/src/graphics/PreviewLoader.cpp b/src/graphics/PreviewLoader.cpp
index d0590f6b28..e1177a8d87 100644
--- a/src/graphics/PreviewLoader.cpp
+++ b/src/graphics/PreviewLoader.cpp
@@ -226,8 +226,6 @@ private:
///
QTimer * delay_refresh_;
///
- Trackable trackable_;
- ///
bool finished_generating_;
/// We don't own this
@@ -244,16 +242,10 @@ lyx::Converter const * PreviewLoader::Impl::pconverter_;
//
PreviewLoader::PreviewLoader(Buffer const & b)
- : pimpl_(new Impl(*this, b))
+ : pimpl_(make_shared<Impl>(*this, b))
{}
-PreviewLoader::~PreviewLoader()
-{
- delete pimpl_;
-}
-
-
PreviewImage const * PreviewLoader::preview(string const & latex_snippet) const
{
return pimpl_->preview(latex_snippet);
@@ -721,9 +713,12 @@ void PreviewLoader::Impl::startLoading(bool wait)
// Initiate the conversion from LaTeX to bitmap images files.
ForkedCall::sigPtr convert_ptr = make_shared<ForkedCall::sig>();
- convert_ptr->connect(ForkedProcess::slot([this](pid_t pid, int retval){
- finishedGenerating(pid, retval);
- }).track_foreign(trackable_.p()));
+ weak_ptr<PreviewLoader::Impl> this_ = parent_.pimpl_;
+ convert_ptr->connect([this_](pid_t pid, int retval){
+ if (auto p = this_.lock()) {
+ p->finishedGenerating(pid, retval);
+ }
+ });
ForkedCall call(buffer_.filePath());
int ret = call.startScript(command, convert_ptr);
diff --git a/src/graphics/PreviewLoader.h b/src/graphics/PreviewLoader.h
index ca22a9fa5c..5d0bf8e234 100644
--- a/src/graphics/PreviewLoader.h
+++ b/src/graphics/PreviewLoader.h
@@ -18,11 +18,12 @@
#ifndef PREVIEWLOADER_H
#define PREVIEWLOADER_H
+#include "ColorCode.h"
#include "support/signals.h"
#include <QObject>
-#include "ColorCode.h"
+#include <memory>
namespace lyx {
@@ -39,8 +40,6 @@ public:
* LaTeX file.
*/
PreviewLoader(Buffer const & buffer);
- ///
- ~PreviewLoader();
/** Is there an image already associated with this snippet of LaTeX?
* If so, returns a pointer to it, else returns 0.
@@ -108,7 +107,7 @@ private:
/// Use the Pimpl idiom to hide the internals.
class Impl;
/// The pointer never changes although *pimpl_'s contents may.
- Impl * const pimpl_;
+ std::shared_ptr<Impl> const pimpl_;
};
} // namespace graphics
diff --git a/src/support/ForkedCalls.cpp b/src/support/ForkedCalls.cpp
index 7718a745ae..387f8561bf 100644
--- a/src/support/ForkedCalls.cpp
+++ b/src/support/ForkedCalls.cpp
@@ -24,6 +24,8 @@
#include "support/bind.h"
#include <cerrno>
+#include <cstring>
+#include <list>
#include <queue>
#include <sstream>
#include <utility>
diff --git a/src/support/Makefile.am b/src/support/Makefile.am
index 83e67eabdf..3dedf57fea 100644
--- a/src/support/Makefile.am
+++ b/src/support/Makefile.am
@@ -29,7 +29,7 @@ liblyxsupport_a_DEPENDENCIES = $(MOCEDFILES)
AM_CPPFLAGS += -I$(srcdir)/.. \
$(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES) \
- $(QT_CPPFLAGS) $(QT_INCLUDES)
+ $(NOD_INCLUDES) $(QT_CPPFLAGS) $(QT_INCLUDES)
liblyxsupport_a_SOURCES = \
FileMonitor.h \
diff --git a/src/support/signals.h b/src/support/signals.h
index f768f2f873..18bc03e117 100644
--- a/src/support/signals.h
+++ b/src/support/signals.h
@@ -12,13 +12,13 @@
#ifndef LYX_SIGNALS_H
#define LYX_SIGNALS_H
-#include <boost/signals2/signal.hpp>
+#include "nod.hpp"
#include <memory>
namespace lyx {
-namespace signals2 = ::boost::signals2;
+namespace signals2 = ::nod;
namespace support {
diff --git a/src/tex2lyx/Makefile.am b/src/tex2lyx/Makefile.am
index 923d6950ec..7ad91a0828 100644
--- a/src/tex2lyx/Makefile.am
+++ b/src/tex2lyx/Makefile.am
@@ -17,7 +17,7 @@ bin_PROGRAMS = tex2lyx
AM_CPPFLAGS += -I$(top_srcdir)/src/tex2lyx \
-I$(top_srcdir)/src -I$(top_builddir) -I$(top_builddir)/src \
- $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES)
+ $(BOOST_INCLUDES) $(ICONV_INCLUDES) $(ZLIB_INCLUDES) $(NOD_INCLUDES)
TEST_FILES = \
test/runtests.cmake \
--
2.28.0.windows.1
--
lyx-devel mailing list
lyx-devel@lists.lyx.org
http://lists.lyx.org/mailman/listinfo/lyx-devel