[niepce] rust: library notifications are implemented in Rust.



commit 5da2476608a08a12da4c2939c53ff5d95effea1b
Author: Hubert Figuière <hub figuiere net>
Date:   Fri Sep 27 19:43:03 2019 -0400

    rust: library notifications are implemented in Rust.
    
    - Update cbindgen
    - library notification type is LibNotification
    - Remove some no longer needed ffi functions

 Cargo.lock                            | 190 ++++++++++++++++++++++++----------
 Cargo.toml                            |   4 +-
 src/engine/Makefile.am                |   2 +-
 src/engine/db/keyword.rs              |   3 +-
 src/engine/db/libmetadata.rs          |   3 +-
 src/engine/db/library.rs              |  43 ++++----
 src/engine/library/commands.rs        |  60 +++++------
 src/engine/library/notification.cpp   |  55 ----------
 src/engine/library/notification.rs    | 185 ++++++++++++++++++---------------
 src/engine/library/thumbnailcache.cpp |  10 +-
 src/fwk/base/propertyvalue.rs         |   4 +-
 src/fwk/utils/exempi.rs               |   3 +-
 src/libraryclient/clientimpl.rs       |   7 +-
 src/libraryclient/libraryclient.cpp   |   6 +-
 src/libraryclient/libraryclient.hpp   |  10 +-
 src/libraryclient/mod.rs              |  45 ++++++--
 src/niepce/notificationcenter.cpp     |  41 +++++---
 src/niepce/notificationcenter.hpp     |  19 ++--
 src/niepce/ui/imageliststore.cpp      |   7 +-
 src/niepce/ui/niepcewindow.cpp        |   5 +-
 src/rust_bindings.hpp                 |   2 +-
 21 files changed, 401 insertions(+), 303 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index a44e023..e7b4e4a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -110,16 +110,18 @@ dependencies = [
 
 [[package]]
 name = "cbindgen"
-version = "0.5.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
  "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "standalone-syn 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -176,6 +178,14 @@ dependencies = [
  "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "cloudabi"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "env_logger"
 version = "0.5.13"
@@ -191,17 +201,17 @@ dependencies = [
 [[package]]
 name = "exempi"
 version = "2.5.0"
-source = 
"git+https://github.com/hfiguiere/exempi-rs.git?rev=d5c013c#d5c013caf38351e69bca13a74cb0fd727d752ef4";
+source = 
"git+https://github.com/hfiguiere/exempi-rs.git?rev=53cfc05#53cfc0527a3644a8b1a04af811bf0672c49b41e7";
 dependencies = [
  "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "exempi-sys 2.5.0 (git+https://github.com/hfiguiere/exempi-rs.git?rev=d5c013c)",
+ "exempi-sys 2.5.0 (git+https://github.com/hfiguiere/exempi-rs.git?rev=53cfc05)",
  "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "exempi-sys"
 version = "2.5.0"
-source = 
"git+https://github.com/hfiguiere/exempi-rs.git?rev=d5c013c#d5c013caf38351e69bca13a74cb0fd727d752ef4";
+source = 
"git+https://github.com/hfiguiere/exempi-rs.git?rev=53cfc05#53cfc0527a3644a8b1a04af811bf0672c49b41e7";
 dependencies = [
  "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -442,14 +452,6 @@ name = "linked-hash-map"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 
-[[package]]
-name = "log"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-dependencies = [
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "log"
 version = "0.4.6"
@@ -492,9 +494,9 @@ name = "niepce_rust"
 version = "0.1.0"
 dependencies = [
  "bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "cbindgen 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cbindgen 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "exempi 2.5.0 (git+https://github.com/hfiguiere/exempi-rs.git?rev=d5c013c)",
+ "exempi 2.5.0 (git+https://github.com/hfiguiere/exempi-rs.git?rev=53cfc05)",
  "gettext-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gio-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -588,7 +590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index";
 
 [[package]]
 name = "proc-macro2"
-version = "0.2.3"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -596,7 +598,7 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "0.3.5"
+version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -620,18 +622,41 @@ dependencies = [
  "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "quote"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rand"
-version = "0.4.6"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
- "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "rand_chacha"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rand_core"
 version = "0.3.1"
@@ -645,6 +670,62 @@ name = "rand_core"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 
+[[package]]
+name = "rand_hc"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_isaac"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_jitter"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_os"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rdrand"
 version = "0.4.0"
@@ -757,24 +838,6 @@ dependencies = [
  "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "standalone-quote"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "standalone-syn"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "standalone-quote 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "strsim"
 version = "0.8.0"
@@ -790,6 +853,16 @@ dependencies = [
  "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "syn"
+version = "0.15.31"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "synom"
 version = "0.11.3"
@@ -799,12 +872,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "tempdir"
-version = "0.3.7"
+name = "tempfile"
+version = "3.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
- "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
  "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -956,16 +1033,17 @@ dependencies = [
 "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
 "checksum cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"e05db47de3b0f09a222fa4bba2eab957d920d4243962a86b2d77ab401e4a359c"
 "checksum cairo-sys-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"90a1ec04603a78c111886a385edcec396dbfbc57ea26b9e74aeea6a1fe55dcca"
-"checksum cbindgen 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"efd8d98004eaf27861f76000ea304b888f869191fefeada9d7496c9c24f111cd"
+"checksum cbindgen 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"31f70db109be74a3dfcb0af4d0d191e52230351477f14c2ed10707c2b0dcfa2e"
 "checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = 
"39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"
 "checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c"
 "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = 
"b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
 "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = 
"77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
 "checksum clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"d7f7c04e52c35222fffcc3a115b5daf5f7e2bfb71c13c4e2321afe1fc71859c2"
 "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
+"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
 "checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = 
"15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
-"checksum exempi 2.5.0 (git+https://github.com/hfiguiere/exempi-rs.git?rev=d5c013c)" = "<none>"
-"checksum exempi-sys 2.5.0 (git+https://github.com/hfiguiere/exempi-rs.git?rev=d5c013c)" = "<none>"
+"checksum exempi 2.5.0 (git+https://github.com/hfiguiere/exempi-rs.git?rev=53cfc05)" = "<none>"
+"checksum exempi-sys 2.5.0 (git+https://github.com/hfiguiere/exempi-rs.git?rev=53cfc05)" = "<none>"
 "checksum fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9"
 "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
 "checksum gdk 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"6243e995f41f3a61a31847e54cc719edce93dd9140c89dca3b9919be1cfe22d5"
@@ -989,7 +1067,6 @@ dependencies = [
 "checksum libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"a5692f82b51823e27c4118b3e5c0d98aee9be90633ebc71ad12afef380b50219"
 "checksum libsqlite3-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"d3711dfd91a1081d2458ad2d06ea30a8755256e74038be2ad927d94e1c955ca8"
 "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
-"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = 
"e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
 "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = 
"c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
 "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
 "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
@@ -1004,14 +1081,22 @@ dependencies = [
 "checksum pango-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"1ee97abcad820f9875e032656257ad1c790e7b11a0e6ce2516a8f5b0d8f8213f"
 "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
 "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = 
"676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
-"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
 "checksum proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = 
"77997c53ae6edd6d187fec07ec41b207063b5ee6f33680e9fa86d405cdd313d4"
+"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = 
"4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
 "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = 
"7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
-"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = 
"552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
+"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = 
"faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
+"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = 
"6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
+"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
 "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
+"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
+"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
+"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
+"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
+"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
+"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
 "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = 
"2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
 "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
@@ -1025,12 +1110,11 @@ dependencies = [
 "checksum serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = 
"652bc323d694dc925829725ec6c890156d8e70ae5202919869cb00fe2eff3788"
 "checksum serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"32f1926285523b2db55df263d2aa4eb69ddcfa7a7eade6430323637866b513ab"
 "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = 
"051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
-"checksum standalone-quote 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"dcedac1d6d98e7e9d1d6e628f5635af9566688ae5f6cea70a3976f495ae8d839"
-"checksum standalone-syn 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"115808f5187c07c23cb93eee49d542fae54c6e8285d3a24c6ff683fcde9243db"
 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = 
"d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
+"checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = 
"d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a"
 "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
-"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = 
"15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
+"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = 
"b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a"
 "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = 
"96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
 "checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330"
 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
diff --git a/Cargo.toml b/Cargo.toml
index a071b59..55ef831 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,7 +6,7 @@ build = "build.rs"
 
 [dependencies]
 chrono = "0.4.0"
-exempi = { version = "2.5.0", git = "https://github.com/hfiguiere/exempi-rs.git";, rev="d5c013c" }
+exempi = { version = "2.5.0", git = "https://github.com/hfiguiere/exempi-rs.git";, rev="53cfc05" }
 gettext-rs = "0.3.0"
 glib-sys = "*"
 glib = { version = "^0.8.0", features = ["subclassing"] }
@@ -24,7 +24,7 @@ try_opt = "0.1.1"
 
 [build-dependencies]
 bindgen = "0.37.0"
-cbindgen = { version = "0.5.2" }
+cbindgen = { version = "0.8.3" }
 pkg-config = "0.3.9"
 
 [lib]
diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am
index 0513d30..95749c1 100644
--- a/src/engine/Makefile.am
+++ b/src/engine/Makefile.am
@@ -28,7 +28,7 @@ libniepceengine_a_SOURCES = \
        db/properties.hpp db/properties.cpp \
        db/properties-def.hpp \
        library/clienttypes.hpp \
-       library/notification.hpp library/notification.cpp \
+       library/notification.hpp \
        library/thumbnailcache.hpp library/thumbnailcache.cpp \
        library/thumbnailnotification.hpp \
        importer/iimporter.hpp \
diff --git a/src/engine/db/keyword.rs b/src/engine/db/keyword.rs
index 08dc0c4..17fce1f 100644
--- a/src/engine/db/keyword.rs
+++ b/src/engine/db/keyword.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - engine/db/keyword.rs
  *
- * Copyright (C) 2017-2018 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@ use std::ffi::CStr;
 use std::ffi::CString;
 use rusqlite;
 
+#[derive(Clone)]
 pub struct Keyword {
     id: LibraryId,
     keyword: String,
diff --git a/src/engine/db/libmetadata.rs b/src/engine/db/libmetadata.rs
index 1c99a52..b6a090d 100644
--- a/src/engine/db/libmetadata.rs
+++ b/src/engine/db/libmetadata.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - eng/db/libmetadata.rs
  *
- * Copyright (C) 2017 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@ use super::{FromDb, LibraryId};
 use root::eng::NiepceProperties as Np;
 use engine::db::libfile::FileType;
 
+#[derive(Clone)]
 pub struct LibMetadata {
     xmp: XmpMeta,
     id: LibraryId,
diff --git a/src/engine/db/library.rs b/src/engine/db/library.rs
index 1cc7064..ffe22dc 100644
--- a/src/engine/db/library.rs
+++ b/src/engine/db/library.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - engine/db/library.rs
  *
- * Copyright (C) 2017-2018 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,8 +34,7 @@ use engine::db::libfile::LibFile;
 use engine::db::libfolder;
 use engine::db::libfolder::LibFolder;
 use engine::db::libmetadata::LibMetadata;
-use engine::library::notification::engine_library_notify;
-use engine::library::notification::Notification as LibNotification;
+use engine::library::notification::LibNotification;
 use fwk;
 use fwk::PropertyValue;
 use root::eng::NiepceProperties as Np;
@@ -73,18 +72,19 @@ pub struct Library {
     dbpath: PathBuf,
     dbconn: Option<rusqlite::Connection>,
     inited: bool,
-    notif_id: u64,
+    sender: glib::Sender<LibNotification>,
 }
 
 impl Library {
     #[cfg(test)]
-    pub fn new_in_memory(notif_id: u64) -> Library {
+    pub fn new_in_memory() -> Library {
+        let (sender, _) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
         let mut lib = Library {
             // maindir: dir,
             dbpath: PathBuf::default(),
             dbconn: None,
             inited: false,
-            notif_id,
+            sender
         };
 
         if let Ok(conn) = rusqlite::Connection::open_in_memory() {
@@ -95,7 +95,8 @@ impl Library {
         lib
     }
 
-    pub fn new(dir: &Path, name: Option<&str>, notif_id: u64) -> Library {
+    pub fn new(dir: &Path, name: Option<&str>,
+               sender: glib::Sender<LibNotification>) -> Library {
         let mut dbpath = PathBuf::from(dir);
         if let Some(filename) = name {
             dbpath.push(filename);
@@ -107,7 +108,7 @@ impl Library {
             dbpath: dbpath.clone(),
             dbconn: None,
             inited: false,
-            notif_id,
+            sender,
         };
 
         if let Ok(conn) = rusqlite::Connection::open(dbpath) {
@@ -120,9 +121,9 @@ impl Library {
 
     fn init(&mut self) -> Result<()> {
         if let Some(ref conn) = self.dbconn {
-            let notif_id = self.notif_id;
+            let sender = self.sender.clone();
             if let Err(err) = conn.create_scalar_function("rewrite_xmp", 0, false, move |_| {
-                Library::notify_by_id(notif_id, Box::new(LibNotification::XmpNeedsUpdate));
+                sender.send(LibNotification::XmpNeedsUpdate);
                 Ok(true)
             }) {
                 err_out!("failed to create scalar function.");
@@ -292,22 +293,14 @@ impl Library {
                 &[],
             ).unwrap();
 
-            self.notify(Box::new(LibNotification::LibCreated));
+            self.notify(LibNotification::LibCreated);
             return Ok(());
         }
         Err(Error::NoSqlDb)
     }
 
-    pub fn notify(&self, notif: Box<LibNotification>) {
-        unsafe {
-            engine_library_notify(self.notif_id, Box::into_raw(notif));
-        }
-    }
-
-    pub fn notify_by_id(id: u64, notif: Box<LibNotification>) {
-        unsafe {
-            engine_library_notify(id, Box::into_raw(notif));
-        }
+    pub fn notify(&self, notif: LibNotification) {
+        self.sender.send(notif);
     }
 
     pub fn add_jpeg_file_to_bundle(&self, file_id: LibraryId, fsfile_id: LibraryId) -> Result<()> {
@@ -734,9 +727,9 @@ impl Library {
                 return Err(Error::InvalidResult);
             }
             let keyword_id = conn.last_insert_rowid();
-            self.notify(Box::new(LibNotification::AddedKeyword(Keyword::new(
+            self.notify(LibNotification::AddedKeyword(Keyword::new(
                 keyword_id, keyword,
-            ))));
+            )));
             return Ok(keyword_id);
         }
         Err(Error::NoSqlDb)
@@ -1076,7 +1069,7 @@ mod test {
     #[test]
     fn library_works() {
 
-        let lib = Library::new_in_memory(0);
+        let lib = Library::new_in_memory();
 
         assert!(lib.is_ok());
         let version = lib.check_database_version();
@@ -1168,7 +1161,7 @@ mod test {
 
     #[test]
     fn file_bundle_import() {
-        let lib = Library::new_in_memory(0);
+        let lib = Library::new_in_memory();
 
         assert!(lib.is_ok());
 
diff --git a/src/engine/library/commands.rs b/src/engine/library/commands.rs
index c75f099..2eea577 100644
--- a/src/engine/library/commands.rs
+++ b/src/engine/library/commands.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - engine/library/commands.rs
  *
- * Copyright (C) 2017 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ use engine::db::filebundle::FileBundle;
 use engine::db::keyword::Keyword;
 use engine::db::label::Label;
 use engine::db::libfolder::LibFolder;
-use super::notification::Notification as LibNotification;
+use super::notification::LibNotification;
 use super::notification::{
     Content,
     Count,
@@ -44,7 +44,7 @@ pub fn cmd_list_all_keywords(lib: &Library) -> bool {
         Ok(list) => {
             // XXX change this to "LoadKeywords"
             for kw in list {
-                lib.notify(Box::new(LibNotification::AddedKeyword(kw)));
+                lib.notify(LibNotification::AddedKeyword(kw));
             }
             true
         },
@@ -60,7 +60,7 @@ pub fn cmd_list_all_folders(lib: &Library) -> bool {
         Ok(list) => {
             // XXX change this to "LoadedFolders"
             for folder in list {
-                lib.notify(Box::new(LibNotification::AddedFolder(folder)));
+                lib.notify(LibNotification::AddedFolder(folder));
             }
             true
         },
@@ -83,7 +83,7 @@ fn get_folder_for_import(lib: &Library, folder: &str) -> library::Result<LibFold
                 match lib.add_folder(&name, Some(String::from(folder))) {
                     Ok(lf) =>  {
                         let libfolder = lf.clone();
-                        lib.notify(Box::new(LibNotification::AddedFolder(lf)));
+                        lib.notify(LibNotification::AddedFolder(lf));
                         Ok(libfolder)
                     },
                     Err(err) => {
@@ -116,7 +116,7 @@ pub fn cmd_import_files(lib: &Library, folder: &str, files: &[String],
                     err_out!("Add bundle failed: {:?}", err);
                 }
             }
-            lib.notify(Box::new(LibNotification::AddedFiles));
+            lib.notify(LibNotification::AddedFiles);
             true
         },
         Err(err) => {
@@ -130,7 +130,7 @@ pub fn cmd_create_folder(lib: &Library, name: &str, path: Option<String>) -> Lib
     match lib.add_folder(name, path) {
         Ok(lf) =>  {
             let id = lf.id();
-            lib.notify(Box::new(LibNotification::AddedFolder(lf)));
+            lib.notify(LibNotification::AddedFolder(lf));
             id
         },
         Err(err) =>  {
@@ -143,7 +143,7 @@ pub fn cmd_create_folder(lib: &Library, name: &str, path: Option<String>) -> Lib
 pub fn cmd_delete_folder(lib: &Library, id: LibraryId) -> bool {
     match lib.delete_folder(id) {
         Ok(_) => {
-            lib.notify(Box::new(LibNotification::FolderDeleted(id)));
+            lib.notify(LibNotification::FolderDeleted(id));
             true
         },
         Err(err) => {
@@ -156,7 +156,7 @@ pub fn cmd_delete_folder(lib: &Library, id: LibraryId) -> bool {
 pub fn cmd_request_metadata(lib: &Library, file_id: LibraryId) -> bool {
     match lib.get_metadata(file_id) {
         Ok(lm) => {
-            lib.notify(Box::new(LibNotification::MetadataQueried(lm)));
+            lib.notify(LibNotification::MetadataQueried(lm));
             true
         },
         Err(err) => {
@@ -169,9 +169,9 @@ pub fn cmd_request_metadata(lib: &Library, file_id: LibraryId) -> bool {
 pub fn cmd_query_folder_content(lib: &Library, folder_id: LibraryId) -> bool {
     match lib.get_folder_content(folder_id) {
         Ok(fl) => {
-            let mut value = Box::new(
-                LibNotification::FolderContentQueried(unsafe { Content::new(folder_id) }));
-            if let LibNotification::FolderContentQueried(ref mut content) = *value {
+            let mut value =
+                LibNotification::FolderContentQueried(unsafe { Content::new(folder_id) });
+            if let LibNotification::FolderContentQueried(ref mut content) = value {
                 for f in fl {
                     unsafe { content.push(Box::into_raw(Box::new(f)) as *mut c_void) };
                 }
@@ -190,8 +190,8 @@ pub fn cmd_set_metadata(lib: &Library, id: LibraryId, meta: Np,
                         value: &PropertyValue) -> bool {
     match lib.set_metadata(id, meta, value) {
         Ok(_) => {
-            lib.notify(Box::new(LibNotification::MetadataChanged(
-                MetadataChange::new(id, meta as u32, Box::new(value.clone())))));
+            lib.notify(LibNotification::MetadataChanged(
+                MetadataChange::new(id, meta as u32, value.clone())));
             true
         },
         Err(err) => {
@@ -204,8 +204,8 @@ pub fn cmd_set_metadata(lib: &Library, id: LibraryId, meta: Np,
 pub fn cmd_count_folder(lib: &Library, id: LibraryId) -> bool {
     match lib.count_folder(id) {
         Ok(count) => {
-            lib.notify(Box::new(LibNotification::FolderCounted(
-                Count{id, count})));
+            lib.notify(LibNotification::FolderCounted(
+                Count{id, count}));
             true
         },
         Err(err) => {
@@ -218,7 +218,7 @@ pub fn cmd_count_folder(lib: &Library, id: LibraryId) -> bool {
 pub fn cmd_add_keyword(lib: &Library, keyword: &str) -> LibraryId {
     match lib.make_keyword(keyword) {
         Ok(id) => {
-            lib.notify(Box::new(LibNotification::AddedKeyword(Keyword::new(id, keyword))));
+            lib.notify(LibNotification::AddedKeyword(Keyword::new(id, keyword)));
             id
         },
         Err(err) => {
@@ -235,7 +235,7 @@ pub fn cmd_query_keyword_content(lib: &Library, keyword_id: LibraryId) -> bool {
             for f in fl {
                 unsafe { content.push(Box::into_raw(Box::new(f)) as *mut c_void) };
             }
-            lib.notify(Box::new(LibNotification::KeywordContentQueried(content)));
+            lib.notify(LibNotification::KeywordContentQueried(content));
             true
         },
         Err(err) => {
@@ -248,8 +248,8 @@ pub fn cmd_query_keyword_content(lib: &Library, keyword_id: LibraryId) -> bool {
 pub fn cmd_count_keyword(lib: &Library, id: LibraryId) -> bool {
     match lib.count_keyword(id) {
         Ok(count) => {
-            lib.notify(Box::new(LibNotification::KeywordCounted(
-                Count{id, count})));
+            lib.notify(LibNotification::KeywordCounted(
+                Count{id, count}));
             true
         },
         Err(err) => {
@@ -273,12 +273,12 @@ pub fn cmd_move_file_to_folder(lib: &Library, file_id: LibraryId, from: LibraryI
                                to: LibraryId) -> bool {
     match lib.move_file_to_folder(file_id, to) {
         Ok(_) => {
-            lib.notify(Box::new(LibNotification::FileMoved(
-                FileMove{file: file_id, from, to})));
-            lib.notify(Box::new(LibNotification::FolderCountChanged(
-                Count{id: from, count: -1})));
-            lib.notify(Box::new(LibNotification::FolderCountChanged(
-                Count{id: to, count: 1})));
+            lib.notify(LibNotification::FileMoved(
+                FileMove{file: file_id, from, to}));
+            lib.notify(LibNotification::FolderCountChanged(
+                Count{id: from, count: -1}));
+            lib.notify(LibNotification::FolderCountChanged(
+                Count{id: to, count: 1}));
             true
         },
         Err(err) => {
@@ -293,7 +293,7 @@ pub fn cmd_list_all_labels(lib: &Library) -> bool {
         Ok(l) => {
             // XXX change this notification type
             for label in l {
-                lib.notify(Box::new(LibNotification::AddedLabel(label)));
+                lib.notify(LibNotification::AddedLabel(label));
             }
             true
         },
@@ -308,7 +308,7 @@ pub fn cmd_create_label(lib: &Library, name: &str, colour: &str) -> LibraryId {
     match lib.add_label(name, colour) {
         Ok(id) => {
             let l = Label::new(id, name, colour);
-            lib.notify(Box::new(LibNotification::AddedLabel(l)));
+            lib.notify(LibNotification::AddedLabel(l));
             id
         },
         Err(err) => {
@@ -321,7 +321,7 @@ pub fn cmd_create_label(lib: &Library, name: &str, colour: &str) -> LibraryId {
 pub fn cmd_delete_label(lib: &Library, label_id: LibraryId) -> bool {
     match lib.delete_label(label_id) {
         Ok(_) => {
-            lib.notify(Box::new(LibNotification::LabelDeleted(label_id)));
+            lib.notify(LibNotification::LabelDeleted(label_id));
             true
         },
         Err(err) => {
@@ -336,7 +336,7 @@ pub fn cmd_update_label(lib: &Library, label_id: LibraryId, name: &str,
     match lib.update_label(label_id, name, colour) {
         Ok(_) => {
             let label = Label::new(label_id, name, colour);
-            lib.notify(Box::new(LibNotification::LabelChanged(label)));
+            lib.notify(LibNotification::LabelChanged(label));
             true
         },
         Err(err) => {
diff --git a/src/engine/library/notification.rs b/src/engine/library/notification.rs
index 286d94c..10b5bbb 100644
--- a/src/engine/library/notification.rs
+++ b/src/engine/library/notification.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - engine/library/notification.rs
  *
- * Copyright (C) 2017-2018 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,11 +26,20 @@ use engine::db::{
 use engine::db::libfile::{
     FileStatus,
 };
+use libraryclient::LcChannel;
 
+#[cfg(not(test))]
 use root::eng::QueriedContent;
-
+#[cfg(not(test))]
 pub type Content = QueriedContent;
 
+// Content need to be stubbed for the test as it is a FFI struct
+// and is missing the proper C++ code.
+#[cfg(test)]
+#[derive(Clone,Copy)]
+pub struct Content {
+}
+
 #[repr(i32)]
 #[allow(non_camel_case_types)]
 pub enum NotificationType {
@@ -58,6 +67,7 @@ pub enum NotificationType {
 }
 
 #[repr(C)]
+#[derive(Clone)]
 pub struct FileMove {
     pub file: LibraryId,
     pub from: LibraryId,
@@ -65,37 +75,49 @@ pub struct FileMove {
 }
 
 #[repr(C)]
+#[derive(Clone)]
 pub struct FileStatusChange {
     pub id: LibraryId,
     pub status: FileStatus,
 }
 
 #[repr(C)]
+#[derive(Clone)]
 pub struct Count {
     pub id: LibraryId,
     pub count: i64,
 }
 
-#[repr(C)]
+#[derive(Clone)]
 pub struct MetadataChange {
     id: LibraryId,
     meta: PropertyIndex,
-    value: *mut PropertyValue,
+    value: PropertyValue,
 }
 
 impl MetadataChange {
-    pub fn new(id: LibraryId, meta: PropertyIndex, value: Box<PropertyValue>) -> Self {
-        MetadataChange {id, meta, value: Box::into_raw(value)}
+    pub fn new(id: LibraryId, meta: PropertyIndex, value: PropertyValue) -> Self {
+        MetadataChange {id, meta, value}
     }
 }
 
-impl Drop for MetadataChange {
-    fn drop(&mut self) {
-        unsafe { Box::from_raw(self.value); }
-    }
+#[no_mangle]
+pub unsafe extern "C" fn metadatachange_get_id(meta: *const MetadataChange) -> LibraryId {
+    (*meta).id
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn metadatachange_get_meta(meta: *const MetadataChange) -> PropertyIndex {
+    (*meta).meta
 }
 
-pub enum Notification {
+#[no_mangle]
+pub unsafe extern "C" fn metadatachange_get_value(meta: *const MetadataChange) -> *const PropertyValue {
+    &(*meta).value
+}
+
+#[derive(Clone)]
+pub enum LibNotification {
     AddedFile,
     AddedFiles,
     AddedFolder(LibFolder),
@@ -118,11 +140,11 @@ pub enum Notification {
     XmpNeedsUpdate,
 }
 
-impl Drop for Notification {
+impl Drop for LibNotification {
     fn drop(&mut self) {
         match *self {
-            Notification::FolderContentQueried(mut c) |
-            Notification::KeywordContentQueried(mut c) => {
+            LibNotification::FolderContentQueried(mut c) |
+            LibNotification::KeywordContentQueried(mut c) => {
                 unsafe { c.destruct(); }
             },
             _ => (),
@@ -130,150 +152,135 @@ impl Drop for Notification {
     }
 }
 
-#[cfg(not(test))]
-#[allow(improper_ctypes)]
-extern "C" {
-    // actually a *mut Notification
-    pub fn engine_library_notify(notif_id: u64, n: *mut Notification);
-}
-
-#[cfg(test)]
-#[no_mangle]
-pub unsafe fn engine_library_notify(_: u64, _: *mut Notification) {
-    // stub for tests
-    // unsafe since it non test function is extern
-}
-
 /// Send a notification for the file status change.
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notify_filestatus_changed(notif_id: u64,
+pub unsafe extern "C" fn engine_library_notify_filestatus_changed(channel: *const LcChannel,
                                                            id: LibraryId,
                                                            status: FileStatus) {
-    let notif = Box::new(Notification::FileStatusChanged(
+    (*channel).0.clone().send(LibNotification::FileStatusChanged(
         FileStatusChange{id, status}));
-    engine_library_notify(notif_id, Box::into_raw(notif));
 }
 
 /// Delete the Notification object.
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_delete(n: *mut Notification) {
+pub unsafe extern "C" fn engine_library_notification_delete(n: *mut LibNotification) {
     Box::from_raw(n);
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_type(n: *const Notification) -> NotificationType {
+pub unsafe extern "C" fn engine_library_notification_type(n: *const LibNotification) -> NotificationType {
     match n.as_ref() {
-        Some(&Notification::AddedFile) => NotificationType::ADDED_FILE,
-        Some(&Notification::AddedFiles) => NotificationType::ADDED_FILES,
-        Some(&Notification::AddedFolder(_)) => NotificationType::ADDED_FOLDER,
-        Some(&Notification::AddedKeyword(_)) => NotificationType::ADDED_KEYWORD,
-        Some(&Notification::AddedLabel(_)) => NotificationType::ADDED_LABEL,
-        Some(&Notification::FileMoved(_)) => NotificationType::FILE_MOVED,
-        Some(&Notification::FileStatusChanged(_)) => NotificationType::FILE_STATUS_CHANGED,
-        Some(&Notification::FolderContentQueried(_)) => NotificationType::FOLDER_CONTENT_QUERIED,
-        Some(&Notification::FolderCounted(_)) => NotificationType::FOLDER_COUNTED,
-        Some(&Notification::FolderCountChanged(_)) => NotificationType::FOLDER_COUNT_CHANGE,
-        Some(&Notification::FolderDeleted(_)) => NotificationType::FOLDER_DELETED,
-        Some(&Notification::KeywordContentQueried(_)) =>
+        Some(&LibNotification::AddedFile) => NotificationType::ADDED_FILE,
+        Some(&LibNotification::AddedFiles) => NotificationType::ADDED_FILES,
+        Some(&LibNotification::AddedFolder(_)) => NotificationType::ADDED_FOLDER,
+        Some(&LibNotification::AddedKeyword(_)) => NotificationType::ADDED_KEYWORD,
+        Some(&LibNotification::AddedLabel(_)) => NotificationType::ADDED_LABEL,
+        Some(&LibNotification::FileMoved(_)) => NotificationType::FILE_MOVED,
+        Some(&LibNotification::FileStatusChanged(_)) => NotificationType::FILE_STATUS_CHANGED,
+        Some(&LibNotification::FolderContentQueried(_)) => NotificationType::FOLDER_CONTENT_QUERIED,
+        Some(&LibNotification::FolderCounted(_)) => NotificationType::FOLDER_COUNTED,
+        Some(&LibNotification::FolderCountChanged(_)) => NotificationType::FOLDER_COUNT_CHANGE,
+        Some(&LibNotification::FolderDeleted(_)) => NotificationType::FOLDER_DELETED,
+        Some(&LibNotification::KeywordContentQueried(_)) =>
             NotificationType::KEYWORD_CONTENT_QUERIED,
-        Some(&Notification::KeywordCounted(_)) => NotificationType::KEYWORD_COUNTED,
-        Some(&Notification::KeywordCountChanged(_)) => NotificationType::KEYWORD_COUNT_CHANGE,
-        Some(&Notification::LabelChanged(_)) => NotificationType::LABEL_CHANGED,
-        Some(&Notification::LabelDeleted(_)) => NotificationType::LABEL_DELETED,
-        Some(&Notification::LibCreated) => NotificationType::NEW_LIBRARY_CREATED,
-        Some(&Notification::MetadataChanged(_)) => NotificationType::METADATA_CHANGED,
-        Some(&Notification::MetadataQueried(_)) => NotificationType::METADATA_QUERIED,
-        Some(&Notification::XmpNeedsUpdate) => NotificationType::XMP_NEEDS_UPDATE,
+        Some(&LibNotification::KeywordCounted(_)) => NotificationType::KEYWORD_COUNTED,
+        Some(&LibNotification::KeywordCountChanged(_)) => NotificationType::KEYWORD_COUNT_CHANGE,
+        Some(&LibNotification::LabelChanged(_)) => NotificationType::LABEL_CHANGED,
+        Some(&LibNotification::LabelDeleted(_)) => NotificationType::LABEL_DELETED,
+        Some(&LibNotification::LibCreated) => NotificationType::NEW_LIBRARY_CREATED,
+        Some(&LibNotification::MetadataChanged(_)) => NotificationType::METADATA_CHANGED,
+        Some(&LibNotification::MetadataQueried(_)) => NotificationType::METADATA_QUERIED,
+        Some(&LibNotification::XmpNeedsUpdate) => NotificationType::XMP_NEEDS_UPDATE,
         None => unreachable!(),
     }
 }
 
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_id(n: *const Notification) -> LibraryId {
+pub unsafe extern "C" fn engine_library_notification_get_id(n: *const LibNotification) -> LibraryId {
     match n.as_ref() {
-        Some(&Notification::MetadataChanged(ref changed)) => changed.id,
-        Some(&Notification::FolderDeleted(id)) => id,
-        Some(&Notification::LabelDeleted(id)) => id,
-        Some(&Notification::FileStatusChanged(ref changed)) => changed.id,
+        Some(&LibNotification::MetadataChanged(ref changed)) => changed.id,
+        Some(&LibNotification::FolderDeleted(id)) => id,
+        Some(&LibNotification::LabelDeleted(id)) => id,
+        Some(&LibNotification::FileStatusChanged(ref changed)) => changed.id,
         _ => unreachable!(),
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_label(n: *const Notification) -> *const Label {
+pub unsafe extern "C" fn engine_library_notification_get_label(n: *const LibNotification) -> *const Label {
     match n.as_ref() {
-        Some(&Notification::AddedLabel(ref l)) |
-        Some(&Notification::LabelChanged(ref l)) => l,
+        Some(&LibNotification::AddedLabel(ref l)) |
+        Some(&LibNotification::LabelChanged(ref l)) => l,
         _ => unreachable!(),
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_filemoved(n: *const Notification) -> *const 
FileMove {
+pub unsafe extern "C" fn engine_library_notification_get_filemoved(n: *const LibNotification) -> *const 
FileMove {
     match n.as_ref() {
-        Some(&Notification::FileMoved(ref m)) => m,
+        Some(&LibNotification::FileMoved(ref m)) => m,
         _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_filestatus(n: *const Notification) -> FileStatus {
+pub unsafe extern "C" fn engine_library_notification_get_filestatus(n: *const LibNotification) -> FileStatus 
{
     match n.as_ref() {
-        Some(&Notification::FileStatusChanged(ref s)) => s.status,
+        Some(&LibNotification::FileStatusChanged(ref s)) => s.status,
         _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_libmetadata(n: *const Notification) -> *const 
LibMetadata {
+pub unsafe extern "C" fn engine_library_notification_get_libmetadata(n: *const LibNotification) -> *const 
LibMetadata {
     match n.as_ref() {
-        Some(&Notification::MetadataQueried(ref m)) => m,
+        Some(&LibNotification::MetadataQueried(ref m)) => m,
         _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_count(n: *const Notification) -> *const Count {
+pub unsafe extern "C" fn engine_library_notification_get_count(n: *const LibNotification) -> *const Count {
     match n.as_ref() {
-        Some(&Notification::FolderCountChanged(ref c)) |
-        Some(&Notification::FolderCounted(ref c)) |
-        Some(&Notification::KeywordCountChanged(ref c)) |
-        Some(&Notification::KeywordCounted(ref c)) =>
+        Some(&LibNotification::FolderCountChanged(ref c)) |
+        Some(&LibNotification::FolderCounted(ref c)) |
+        Some(&LibNotification::KeywordCountChanged(ref c)) |
+        Some(&LibNotification::KeywordCounted(ref c)) =>
             c,
         _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_metadatachange(n: *const Notification) -> *const 
MetadataChange {
+pub unsafe extern "C" fn engine_library_notification_get_metadatachange(n: *const LibNotification) -> *const 
MetadataChange {
     match n.as_ref() {
-        Some(&Notification::MetadataChanged(ref c)) => c,
+        Some(&LibNotification::MetadataChanged(ref c)) => c,
         _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_libfolder(n: *const Notification) -> *const 
LibFolder {
+pub unsafe extern "C" fn engine_library_notification_get_libfolder(n: *const LibNotification) -> *const 
LibFolder {
     match n.as_ref() {
-        Some(&Notification::AddedFolder(ref f)) => f,
+        Some(&LibNotification::AddedFolder(ref f)) => f,
         _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_keyword(n: *const Notification) -> *const Keyword {
+pub unsafe extern "C" fn engine_library_notification_get_keyword(n: *const LibNotification) -> *const 
Keyword {
     match n.as_ref() {
-        Some(&Notification::AddedKeyword(ref f)) => f,
+        Some(&LibNotification::AddedKeyword(ref f)) => f,
         _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn engine_library_notification_get_content(n: *const Notification) -> *const Content {
+pub unsafe extern "C" fn engine_library_notification_get_content(n: *const LibNotification) -> *const 
Content {
     match n.as_ref() {
-        Some(&Notification::FolderContentQueried(ref c)) |
-        Some(&Notification::KeywordContentQueried(ref c)) => {
+        Some(&LibNotification::FolderContentQueried(ref c)) |
+        Some(&LibNotification::KeywordContentQueried(ref c)) => {
             c
         },
         _ => {
@@ -281,3 +288,19 @@ pub unsafe extern "C" fn engine_library_notification_get_content(n: *const Notif
         }
     }
 }
+
+#[cfg(test)]
+use libc::c_void;
+
+#[cfg(test)]
+impl Content {
+    pub unsafe fn new(_: LibraryId) -> Self {
+        Content{}
+    }
+
+    pub unsafe fn push(&mut self, _: *mut c_void) {
+    }
+
+    pub unsafe fn destruct(&self) {
+    }
+}
diff --git a/src/engine/library/thumbnailcache.cpp b/src/engine/library/thumbnailcache.cpp
index 9eab43a..f965669 100644
--- a/src/engine/library/thumbnailcache.cpp
+++ b/src/engine/library/thumbnailcache.cpp
@@ -25,6 +25,7 @@
 #include <glibmm/miscutils.h>
 
 #include "niepce/notifications.hpp"
+#include "niepce/notificationcenter.hpp"
 #include "fwk/base/debug.hpp"
 #include "fwk/utils/pathutils.hpp"
 #include "fwk/toolkit/thumbnail.hpp"
@@ -98,8 +99,13 @@ void ThumbnailCache::execute(const ptr_t & task)
     fwk::Thumbnail pix = getThumbnail(libfile, w, h, dest);
     if (!fwk::path_exists(path)) {
         DBG_OUT("file doesn't exist");
-        ffi::engine_library_notify_filestatus_changed(m_notif_id, id,
-                                                      FileStatus::Missing);
+        auto wnc = fwk::NotificationCenter::get_nc(m_notif_id);
+        auto nc = wnc.lock();
+        if (nc) {
+            auto lnc = std::static_pointer_cast<niepce::NotificationCenter>(nc);
+            ffi::engine_library_notify_filestatus_changed(lnc->get_channel().get(), id,
+                                                          FileStatus::Missing);
+        }
     }
 
     if(!pix.ok()) {
diff --git a/src/fwk/base/propertyvalue.rs b/src/fwk/base/propertyvalue.rs
index fb80cca..2332648 100644
--- a/src/fwk/base/propertyvalue.rs
+++ b/src/fwk/base/propertyvalue.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/base/propertyvalue.rs
  *
- * Copyright (C) 2017 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ pub enum PropertyValue {
     Date(Date)
 }
 
-impl PropertyValue {
+unsafe impl Send for PropertyValue {
 }
 
 #[no_mangle]
diff --git a/src/fwk/utils/exempi.rs b/src/fwk/utils/exempi.rs
index df02194..0f05edf 100644
--- a/src/fwk/utils/exempi.rs
+++ b/src/fwk/utils/exempi.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/utils/exempi.rs
  *
- * Copyright (C) 2017-2018 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -111,6 +111,7 @@ impl ExempiManager {
     }
 }
 
+#[derive(Clone)]
 pub struct XmpMeta {
     pub xmp: Xmp,
     keywords: Vec<String>,
diff --git a/src/libraryclient/clientimpl.rs b/src/libraryclient/clientimpl.rs
index 439acee..cc65eaf 100644
--- a/src/libraryclient/clientimpl.rs
+++ b/src/libraryclient/clientimpl.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - libraryclient/clientimpl.rs
  *
- * Copyright (C) 2017-2018 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@ use engine::db::{Library, LibraryId};
 use engine::db::library::Managed;
 use engine::library::op::Op;
 use engine::library::commands;
+use engine::library::notification::LibNotification;
 use super::clientinterface::{ClientInterface,ClientInterfaceSync};
 use root::eng::NiepceProperties as Np;
 
@@ -45,14 +46,14 @@ impl Drop for ClientImpl {
 
 impl ClientImpl {
 
-    pub fn new(dir: PathBuf, notif_id: u64) -> ClientImpl {
+    pub fn new(dir: PathBuf, sender: glib::Sender<LibNotification>) -> ClientImpl {
         let tasks = sync::Arc::new((sync::Mutex::new(VecDeque::new()), sync::Condvar::new()));
         let mut terminate = sync::Arc::new(atomic::AtomicBool::new(false));
         let tasks2 = tasks.clone();
         let terminate2 = terminate.clone();
 
         /* let thread = */ thread::spawn(move || {
-            let library = Library::new(&dir, None, notif_id);
+            let library = Library::new(&dir, None, sender);
             Self::main(&mut terminate, &tasks, &library);
         });
 
diff --git a/src/libraryclient/libraryclient.cpp b/src/libraryclient/libraryclient.cpp
index 161b4c7..0f8b9d9 100644
--- a/src/libraryclient/libraryclient.cpp
+++ b/src/libraryclient/libraryclient.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - libraryclient/libraryclient.cpp
  *
- * Copyright (C) 2007-2018 Hubert Figuière
+ * Copyright (C) 2007-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -32,9 +32,9 @@ namespace libraryclient {
 const char * s_thumbcacheDirname = "thumbcache";
 
 LibraryClient::LibraryClient(const fwk::Moniker & moniker,
-                             uint64_t notif_id)
+                             const std::shared_ptr<ffi::LcChannel>& channel, uint64_t notif_id)
     : m_client(
-        ffi::libraryclient_new(moniker.path().c_str(), notif_id),
+        ffi::libraryclient_new(moniker.path().c_str(), channel.get()),
         ffi::libraryclient_delete)
     , m_thumbnailCache(moniker.path() + "/" + s_thumbcacheDirname, notif_id)
     , m_uidataprovider(new UIDataProvider())
diff --git a/src/libraryclient/libraryclient.hpp b/src/libraryclient/libraryclient.hpp
index 61a60d8..4ca1252 100644
--- a/src/libraryclient/libraryclient.hpp
+++ b/src/libraryclient/libraryclient.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - libraryclient/libraryclient.hpp
  *
- * Copyright (C) 2007-2018 Hubert Figuière
+ * Copyright (C) 2007-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,8 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _LIBRARYCLIENT_H_
-#define _LIBRARYCLIENT_H_
+#pragma once
 
 #include <string>
 #include <memory>
@@ -41,7 +40,8 @@ public:
     LibraryClient() = delete;
     LibraryClient& operator=(const LibraryClient&) = delete;
 
-    LibraryClient(const fwk::Moniker & moniker, uint64_t notif_id);
+    LibraryClient(const fwk::Moniker & moniker, const std::shared_ptr<ffi::LcChannel>& channel,
+                  uint64_t notif_id);
     virtual ~LibraryClient();
 
     eng::ThumbnailCache & thumbnailCache()
@@ -63,8 +63,6 @@ private:
 typedef std::shared_ptr<LibraryClient> LibraryClientPtr;
 
 }
-
-#endif
 /*
   Local Variables:
   mode:c++
diff --git a/src/libraryclient/mod.rs b/src/libraryclient/mod.rs
index 7310ef9..9410727 100644
--- a/src/libraryclient/mod.rs
+++ b/src/libraryclient/mod.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - libraryclient/mod.rs
  *
- * Copyright (C) 2017 Hubert Figuière
+ * Copyright (C) 2017-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@ pub mod clientinterface;
 
 pub use self::clientinterface::{ClientInterface,ClientInterfaceSync};
 
-use libc::c_char;
+use libc::{c_char, c_void};
 use std::ffi::CStr;
 use std::path::PathBuf;
 use std::sync::Arc;
@@ -31,9 +31,13 @@ use fwk::base::PropertyValue;
 use self::clientimpl::ClientImpl;
 use engine::db::LibraryId;
 use engine::db::library::Managed;
+use engine::library::notification::LibNotification;
 use root::fwk::FileList;
 use root::eng::NiepceProperties as Np;
 
+/// Wrapper type for the channel tuple to get passed down to the unsafe C++ code.
+pub struct LcChannel(pub glib::Sender<LibNotification>, glib::SourceId);
+
 /// Wrap the libclient Arc so that it can be passed around
 /// Used in the ffi for example.
 pub struct LibraryClientWrapper {
@@ -41,8 +45,8 @@ pub struct LibraryClientWrapper {
 }
 
 impl LibraryClientWrapper {
-    pub fn new(dir: PathBuf, notif_id: u64) -> LibraryClientWrapper {
-        LibraryClientWrapper { client: Arc::new(LibraryClient::new(dir, notif_id)) }
+    pub fn new(dir: PathBuf, sender: glib::Sender<LibNotification>) -> LibraryClientWrapper {
+        LibraryClientWrapper { client: Arc::new(LibraryClient::new(dir, sender)) }
     }
 
     /// unwrap the mutable client Arc
@@ -61,9 +65,9 @@ pub struct LibraryClient {
 
 impl LibraryClient {
 
-    pub fn new(dir: PathBuf, notif_id: u64) -> LibraryClient {
+    pub fn new(dir: PathBuf, sender: glib::Sender<LibNotification>) -> LibraryClient {
         LibraryClient {
-            pimpl: ClientImpl::new(dir, notif_id),
+            pimpl: ClientImpl::new(dir, sender),
             trash_id: 0
         }
     }
@@ -168,9 +172,34 @@ impl ClientInterfaceSync for LibraryClient {
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn libraryclient_new(path: *const c_char, notif_id: u64) -> *mut LibraryClientWrapper {
+pub unsafe extern "C" fn lcchannel_new(cb: extern fn(n: *const LibNotification, data: *mut c_void) -> i32, 
data: *mut c_void) -> *mut LcChannel {
+    let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
+    let source_id = receiver.attach(None, move |n: LibNotification| {
+        let mut continuation = false;
+        if cb(&n, data) != 0 {
+            continuation = true;
+        }
+        glib::Continue(continuation)
+    });
+    Box::into_raw(Box::new(LcChannel(sender, source_id)))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lcchannel_delete(obj: *mut LcChannel) {
+    Box::from_raw(obj);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lcchannel_destroy(obj: *mut LcChannel) {
+    if let Some(source) = glib::MainContext::default().find_source_by_id(&(*obj).1) {
+        source.destroy();
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn libraryclient_new(path: *const c_char, channel: *const LcChannel) -> *mut 
LibraryClientWrapper {
     let dir = PathBuf::from(&*CStr::from_ptr(path).to_string_lossy());
-    Box::into_raw(Box::new(LibraryClientWrapper::new(dir, notif_id)))
+    Box::into_raw(Box::new(LibraryClientWrapper::new(dir, (*channel).0.clone())))
 }
 
 #[no_mangle]
diff --git a/src/niepce/notificationcenter.cpp b/src/niepce/notificationcenter.cpp
index 77128a8..abbdcd6 100644
--- a/src/niepce/notificationcenter.cpp
+++ b/src/niepce/notificationcenter.cpp
@@ -1,7 +1,7 @@
 /*
- * niepce - niepce/notificationcenter.hpp
+ * niepce - niepce/notificationcenter.cpp
  *
- * Copyright (C) 2009, 2013 Hubert Figuiere
+ * Copyright (C) 2009-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,26 +26,39 @@
 
 namespace niepce {
 
+int32_t NotificationCenter::channel_callback(const eng::LibNotification *notification, void *data)
+{
+    DBG_ASSERT(data, "Notification center is NULL");
+    if (data) {
+        auto self = (NotificationCenter*)data;
+        self->dispatch_lib_notification(notification);
+        DBG_OUT("callback called");
+    }
+    return 1;
+}
+
 NotificationCenter::NotificationCenter(uint64_t notif_id)
     : fwk::NotificationCenter(notif_id)
+    , m_channel(ffi::lcchannel_new(&channel_callback, this), ffi::lcchannel_delete)
 {
-  subscribe(NOTIFICATION_LIB,
-            sigc::mem_fun(*this, &NotificationCenter::dispatch_notification));
-  subscribe(NOTIFICATION_THUMBNAIL,
-            sigc::mem_fun(*this, &NotificationCenter::dispatch_notification));
+    subscribe(NOTIFICATION_THUMBNAIL,
+              sigc::mem_fun(*this, &NotificationCenter::dispatch_notification));
 }
 
+NotificationCenter::~NotificationCenter()
+{
+    ffi::lcchannel_destroy(m_channel.get());
+}
 
-void NotificationCenter::dispatch_notification(const fwk::Notification::Ptr &n)
+void NotificationCenter::dispatch_lib_notification(const eng::LibNotification *n) const
+{
+    signal_lib_notification(*n);
+}
+
+void NotificationCenter::dispatch_notification(const fwk::Notification::Ptr &n) const
 {
     try {
         switch(n->type()) {
-        case NOTIFICATION_LIB:
-        {
-            auto ln = boost::any_cast<eng::LibNotificationPtr>(n->data());
-            signal_lib_notification(*ln);
-            break;
-        }
         case NOTIFICATION_THUMBNAIL:
         {
             eng::ThumbnailNotification tn
@@ -54,6 +67,7 @@ void NotificationCenter::dispatch_notification(const fwk::Notification::Ptr &n)
             break;
         }
         default:
+            ERR_OUT("Unhandled notification type %d", n->type());
             break;
         }
     }
@@ -73,7 +87,6 @@ void NotificationCenter::dispatch_notification(const fwk::Notification::Ptr &n)
     }
 }
 
-
 }
 /*
   Local Variables:
diff --git a/src/niepce/notificationcenter.hpp b/src/niepce/notificationcenter.hpp
index e4c156d..44f4541 100644
--- a/src/niepce/notificationcenter.hpp
+++ b/src/niepce/notificationcenter.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - niepce/notificationcenter.hpp
  *
- * Copyright (C) 2009-2013 Hubert Figuiere
+ * Copyright (C) 2009-2019 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,9 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-
-#ifndef __NIEPCE_NOTIFICATIONCENTER_HPP_
-#define __NIEPCE_NOTIFICATIONCENTER_HPP_
+#pragma once
 
 #include <memory>
 #include <sigc++/signal.h>
@@ -28,14 +26,14 @@
 #include "engine/library/notification.hpp"
 #include "engine/library/thumbnailnotification.hpp"
 
-
 namespace niepce {
 
-
 class NotificationCenter
   : public fwk::NotificationCenter
 {
 public:
+  ~NotificationCenter();
+
   typedef std::shared_ptr<NotificationCenter> Ptr;
   static Ptr make(uint64_t notif_id)
     {
@@ -47,16 +45,19 @@ public:
   sigc::signal<void, const eng::LibNotification &> signal_lib_notification;
   sigc::signal<void, const eng::ThumbnailNotification &> signal_thumbnail_notification;
 
+  const std::shared_ptr<ffi::LcChannel>& get_channel() const
+    { return m_channel; };
 protected:
   NotificationCenter(uint64_t notif_id);
 
 private:
-  void dispatch_notification(const fwk::Notification::Ptr &n);
+  static int32_t channel_callback(const eng::LibNotification *notification, void *data);
+  void dispatch_lib_notification(const eng::LibNotification *n) const;
+  void dispatch_notification(const fwk::Notification::Ptr &n) const;
+  std::shared_ptr<ffi::LcChannel> m_channel;
 };
 
 }
-
-#endif
 /*
   Local Variables:
   mode:c++
diff --git a/src/niepce/ui/imageliststore.cpp b/src/niepce/ui/imageliststore.cpp
index 32a9ec3..813686b 100644
--- a/src/niepce/ui/imageliststore.cpp
+++ b/src/niepce/ui/imageliststore.cpp
@@ -167,18 +167,19 @@ void ImageListStore::on_lib_notification(const eng::LibNotification &ln)
     case eng::NotificationType::METADATA_CHANGED:
     {
         auto m = engine_library_notification_get_metadatachange(&ln);
-        const fwk::PropertyIndex& prop = m->meta;
+        const fwk::PropertyIndex& prop = ffi::metadatachange_get_meta(m);
         DBG_OUT("metadata changed %s", eng::_propertyName(prop));
         // only interested in a few props
         if(is_property_interesting(prop)) {
             std::map<eng::library_id_t, Gtk::TreeIter>::const_iterator iter =
-                m_idmap.find(m->id);
+                m_idmap.find(ffi::metadatachange_get_id(m));
             if(iter != m_idmap.end()) {
                 Gtk::TreeRow row = *(iter->second);
                 //
                 eng::LibFilePtr file = row[m_columns.m_libfile];
                 engine_db_libfile_set_property(
-                    file.get(), prop, fwk_property_value_get_integer(m->value));
+                    file.get(), prop, fwk_property_value_get_integer(
+                        ffi::metadatachange_get_value(m)));
                 row[m_columns.m_libfile] = file;
             }
         }
diff --git a/src/niepce/ui/niepcewindow.cpp b/src/niepce/ui/niepcewindow.cpp
index 33dccb5..28d2c7a 100644
--- a/src/niepce/ui/niepcewindow.cpp
+++ b/src/niepce/ui/niepcewindow.cpp
@@ -372,8 +372,9 @@ std::string NiepceWindow::prompt_open_library()
 bool NiepceWindow::open_library(const std::string & libMoniker)
 {
     fwk::Moniker mon = fwk::Moniker(libMoniker);
-    m_libClient = LibraryClientPtr(new LibraryClient(mon,
-                                                     m_notifcenter->id()));
+    m_libClient
+        = LibraryClientPtr(new LibraryClient(
+                               mon, m_notifcenter->get_channel(), m_notifcenter->id()));
     // XXX ensure the library is open.
     set_title(libMoniker);
     m_library_cfg
diff --git a/src/rust_bindings.hpp b/src/rust_bindings.hpp
index 0afbab9..8aaea37 100644
--- a/src/rust_bindings.hpp
+++ b/src/rust_bindings.hpp
@@ -66,7 +66,7 @@ typedef ffi::LibFolder LibFolder;
 typedef ffi::LibMetadata LibMetadata;
 typedef ffi::Label Label;
 typedef ffi::Managed Managed;
-typedef ffi::Notification LibNotification;
+typedef ffi::LibNotification LibNotification;
 typedef ffi::NotificationType NotificationType;
 typedef ffi::FolderVirtualType FolderVirtualType;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]