Notification support via libnotify (#270)

* add external sources for (d)notify with README and license statements
* add new logAndNotify function, make building a compile time option
* use logAndNotify and main.d, make timeout message silent
* update documentation for notification support
* add command line switch --disable-notifications
* add build-deps for libnotify in README.md
This commit is contained in:
Norbert Preining 2018-12-06 04:19:00 +09:00 committed by abraunegg
parent 487cfab8d1
commit cc6cbf5ac7
9 changed files with 649 additions and 14 deletions

View file

@ -1,5 +1,9 @@
DC ?= dmd
DFLAGS += -w -g -ofonedrive -O -L-lcurl -L-lsqlite3 -L-ldl -J.
ifdef NOTIFICATIONS
DFLAGSNOTIFICATIONS ?= -version=NoPragma -version=NoGdk -version=Notifications \
-L-lgmodule-2.0 -L-lglib-2.0 -L-lnotify
endif
DFLAGS += -w -g -ofonedrive -O -L-lcurl -L-lsqlite3 $(DFLAGSNOTIFICATIONS) -L-ldl -J.
PREFIX ?= /usr/local
DOCDIR ?= $(PREFIX)/share/doc/onedrive
MANDIR ?= $(PREFIX)/share/man/man1
@ -26,6 +30,10 @@ SOURCES = \
src/util.d \
src/progress.d
ifdef NOTIFICATIONS
SOURCES += src/notifications/notify.d src/notifications/dnotify.d
endif
all: onedrive onedrive.service onedrive.1
clean:

View file

@ -8,6 +8,7 @@
* Support OneDrive for Business (part of Office 365)
* Shared folders (OneDrive Personal)
* SharePoint / Office 365 Shared Libraries (refer to README.Office365.md to configure)
* Notifications
### What's missing:
* While local changes are uploaded right away, remote changes are delayed
@ -26,6 +27,10 @@ sudo apt install libcurl4-openssl-dev
sudo apt install libsqlite3-dev
curl -fsS https://dlang.org/install.sh | bash -s dmd
```
For notifications the following is necessary:
```
sudo apt install libnotify-dev
```
### Dependencies: Ubuntu - i386 / i686
**Note:** Validated with `Linux ubuntu-i386-vm 4.13.0-36-generic #40~16.04.1-Ubuntu SMP Fri Feb 16 23:26:51 UTC 2018 i686 i686 i686 GNU/Linux` and DMD 2.081.1
@ -35,6 +40,10 @@ sudo apt install libcurl4-openssl-dev
sudo apt install libsqlite3-dev
curl -fsS https://dlang.org/install.sh | bash -s dmd
```
For notifications the following is necessary:
```
sudo apt install libnotify-dev
```
### Dependencies: Debian - i386 / i686
**Note:** Validated with `Linux debian-i386 4.9.0-7-686-pae #1 SMP Debian 4.9.110-1 (2018-07-05) i686 GNU/Linux` and LDC - the LLVM D compiler (1.8.0).
@ -56,6 +65,10 @@ wget http://ftp.us.debian.org/debian/pool/main/l/llvm-toolchain-5.0/libllvm5.0_5
wget http://ftp.us.debian.org/debian/pool/main/n/ncurses/libtinfo6_6.1+20180714-1_i386.deb
sudo dpkg -i ./*.deb
```
For notifications the following is necessary:
```
sudo apt install libnotify-dev
```
### Dependencies: Fedora < Version 18 / CentOS / RHEL
```
@ -64,6 +77,10 @@ sudo yum install libcurl-devel
sudo yum install sqlite-devel
curl -fsS https://dlang.org/install.sh | bash -s dmd
```
For notifications the following is necessary:
```
sudo yum install libnotify-devel
```
### Dependencies: Fedora > Version 18
```
@ -72,11 +89,19 @@ sudo dnf install libcurl-devel
sudo dnf install sqlite-devel
curl -fsS https://dlang.org/install.sh | bash -s dmd
```
For notifications the following is necessary:
```
sudo yum install libnotify-devel
```
### Dependencies: Arch Linux
```
sudo pacman -S curl sqlite dmd
```
For notifications the following is necessary:
```
sudo pacman -S libnotify
```
### Dependencies: Raspbian (ARMHF)
```
@ -85,6 +110,10 @@ sudo apt-get install libsqlite3-dev
wget https://github.com/ldc-developers/ldc/releases/download/v1.11.0/ldc2-1.11.0-linux-armhf.tar.xz
tar -xvf ldc2-1.11.0-linux-armhf.tar.xz
```
For notifications the following is necessary:
```
sudo apt install libnotify-dev
```
### Dependencies: Debian (ARM64)
```
@ -93,6 +122,10 @@ sudo apt-get install libsqlite3-dev
wget https://github.com/ldc-developers/ldc/releases/download/v1.11.0/ldc2-1.11.0-linux-aarch64.tar.xz
tar -xvf ldc2-1.11.0-linux-aarch64.tar.xz
```
For notifications the following is necessary:
```
sudo apt install libnotify-dev
```
### Dependencies: Gentoo
```
@ -101,11 +134,20 @@ sudo layman -a dlang
```
Add ebuild from contrib/gentoo to a local overlay to use.
For notifications the following is necessary:
```
sudo emerge x11-libs/libnotify
```
### Dependencies: OpenSuSE Leap 15.0
```
sudo zypper addrepo --check --refresh --name "D" http://download.opensuse.org/repositories/devel:/languages:/D/openSUSE_Leap_15.0/devel:languages:D.repo
sudo zypper install git libcurl-devel sqlite3-devel D:dmd D:libphobos2-0_81 D:phobos-devel D:phobos-devel-static
```
For notifications the following is necessary:
```
sudo zypper install libnotify-devel
```
## Compilation & Installation
### Building using DMD Reference Compiler:
@ -126,6 +168,13 @@ make
sudo make install
```
### Build options ###
By passing `NOTIFICATIONS=1` to the `make` call, notifications via
libnotify are enabled. Necessary libraries are
`gmodule-2.0`, `glib-2.0`, and `notify`. If these libraries are
named differently on the build system, the make variable
`DFLAGSNOTIFICATIONS` can be adjusted.
### Building using a different compiler (for example [LDC](https://wiki.dlang.org/LDC)):
#### Debian - i386 / i686
```

View file

@ -27,6 +27,9 @@ Debug OneDrive HTTPS communication.
\fB\-d \-\-download\-only\fP
Only download remote changes
.TP
\fB\-\-disable\-notifications\fP
Do not use desktop notifications in monitor mode
.TP
\fB\-\-disable\-upload\-validation\fP
Disable upload validation when uploading to OneDrive
.TP
@ -191,6 +194,15 @@ All logfiles will be in the format of \fB%username%.onedrive.log\fP,
where \fB%username%\fP represents the user who ran the client.
.SH NOTIFICATIONS
If OneDrive has been compiled with support for notifications, a running
\fBonedrive\fP in monitor mode will send notifications about
initialization and errors via libnotify to the dbus.
Note that this does not work if \fBonedrive\fP is started as root
for a user via the \fBonedrive@<username>\fP service.
.SH SEE ALSO
Further examples and documentation is available in

View file

@ -2,13 +2,19 @@ import std.stdio;
import std.file;
import std.datetime;
import std.process;
import std.conv;
import core.sys.posix.pwd, core.sys.posix.unistd, core.stdc.string : strlen;
import std.algorithm : splitter;
version(Notifications) {
import dnotify;
}
// enable verbose logging
bool verbose;
bool writeLogFile = false;
private bool doNotifications;
// shared string variable for username
string username;
string logFilePath;
@ -33,6 +39,11 @@ void init(string logDir)
}
}
void setNotifications(bool value)
{
doNotifications = value;
}
void log(T...)(T args)
{
writeln(args);
@ -42,6 +53,12 @@ void log(T...)(T args)
}
}
void logAndNotify(T...)(T args)
{
notify(args);
log(args);
}
void fileOnly(T...)(T args)
{
if(writeLogFile){
@ -70,6 +87,32 @@ void error(T...)(T args)
}
}
void errorAndNotify(T...)(T args)
{
notify(args);
error(args);
}
void notify(T...)(T args)
{
version(Notifications) {
if (doNotifications) {
string result;
foreach (index, arg; args) {
result ~= to!string(arg);
if (index != args.length - 1)
result ~= " ";
}
auto n = new Notification("OneDrive", result, "IGNORED");
try {
n.show();
} catch (Throwable e) {
vlog("Got exception from showing notification: ", e);
}
}
}
}
private void logfileWriteLine(T...)(T args)
{
// Write to log file
@ -105,4 +148,4 @@ private string getUserName()
// Unknown user?
return "unknown";
}
}
}

View file

@ -90,6 +90,8 @@ int main(string[] args)
bool disableUploadValidation = false;
// SharePoint / Office 365 Shared Library name to query
string o365SharedLibraryName;
// Do not use notifications in monitor mode
bool disableNotifications = false;
try {
auto opt = getopt(
@ -101,6 +103,7 @@ int main(string[] args)
"create-directory", "Create a directory on OneDrive - no sync will be performed.", &createDirectory,
"destination-directory", "Destination directory for renamed or move on OneDrive - no sync will be performed.", &destinationDirectory,
"debug-https", "Debug OneDrive HTTPS communication.", &debugHttp,
"disable-notifications", "Do not use desktop notifications in monitor mode.", &disableNotifications,
"download-only|d", "Only download remote changes", &downloadOnly,
"disable-upload-validation", "Disable upload validation when uploading to OneDrive", &disableUploadValidation,
"enable-logging", "Enable client activity to a separate log file", &enableLogFile,
@ -134,7 +137,7 @@ int main(string[] args)
log.error("Try 'onedrive -h' for more information");
return EXIT_FAILURE;
}
// disable buffering on stdout
stdout.setvbuf(0, _IONBF);
@ -158,6 +161,9 @@ int main(string[] args)
log.vlog("Using logfile dir: ", logDir);
log.init(logDir);
}
// Configure whether notifications are used
log.setNotifications(monitor && !disableNotifications);
// command line parameters override the config
if (syncDirName) cfg.setValue("sync_dir", syncDirName.expandTilde().absolutePath());
@ -166,7 +172,7 @@ int main(string[] args)
// upgrades
if (exists(configDirName ~ "/items.db")) {
remove(configDirName ~ "/items.db");
log.log("Database schema changed, resync needed");
log.logAndNotify("Database schema changed, resync needed");
resync = true;
}
@ -257,7 +263,7 @@ int main(string[] args)
selectiveSync.setMask(cfg.getValue("skip_file"));
// Initialise the sync engine
log.log("Initializing the Synchronization Engine ...");
log.logAndNotify("Initializing the Synchronization Engine ...");
auto sync = new SyncEngine(cfg, onedrive, itemdb, selectiveSync);
try {
@ -283,7 +289,7 @@ int main(string[] args)
if (checkMount) {
// we were asked to check the mounts
if (exists(syncDir ~ "/.nosync")) {
log.log("\nERROR: .nosync file found. Aborting synchronization process to safeguard data.");
log.logAndNotify("ERROR: .nosync file found. Aborting synchronization process to safeguard data.");
onedrive.http.shutdown();
return EXIT_FAILURE;
}
@ -324,7 +330,7 @@ int main(string[] args)
// Does the directory we want to sync actually exist?
if (!exists(singleDirectory)){
// the requested directory does not exist ..
log.log("The requested local directory does not exist. Please check ~/OneDrive/ for requested path");
log.logAndNotify("ERROR: The requested local directory does not exist. Please check ~/OneDrive/ for requested path");
onedrive.http.shutdown();
return EXIT_FAILURE;
}
@ -336,7 +342,7 @@ int main(string[] args)
}
if (monitor) {
log.log("Initializing monitor ...");
log.logAndNotify("Initializing monitor ...");
log.log("OneDrive monitor interval (seconds): ", to!long(cfg.getValue("monitor_interval")));
Monitor m = new Monitor(selectiveSync);
m.onDirCreated = delegate(string path) {
@ -344,7 +350,7 @@ int main(string[] args)
try {
sync.scanForDifferences(path);
} catch(Exception e) {
log.log(e.msg);
log.logAndNotify(e.msg);
}
};
m.onFileChanged = delegate(string path) {
@ -352,7 +358,7 @@ int main(string[] args)
try {
sync.scanForDifferences(path);
} catch(Exception e) {
log.log(e.msg);
log.logAndNotify(e.msg);
}
};
m.onDelete = delegate(string path) {
@ -360,7 +366,7 @@ int main(string[] args)
try {
sync.deleteByPath(path);
} catch(Exception e) {
log.log(e.msg);
log.logAndNotify(e.msg);
}
};
m.onMove = delegate(string from, string to) {
@ -368,7 +374,7 @@ int main(string[] args)
try {
sync.uploadMoveItem(from, to);
} catch(Exception e) {
log.log(e.msg);
log.logAndNotify(e.msg);
}
};
// initialise the monitor class
@ -395,6 +401,7 @@ int main(string[] args)
// TODO better check of type of exception from Curl
// could be either timeout of operation of connection error
// No network connection to OneDrive Service
// Don't overload notifications
log.log("No network connection to Microsoft OneDrive Service, skipping sync");
}
// performSync complete, set lastCheckTime to current time
@ -502,7 +509,8 @@ void performSync(SyncEngine sync, string singleDirectory, bool downloadOnly, boo
count = -1;
} catch (Exception e) {
if (++count == 3) throw e;
else log.log(e.msg);
else log.logAndNotify(e.msg);
}
} while (count != -1);
}

10
src/notifications/README Normal file
View file

@ -0,0 +1,10 @@
The files in this directory have been obtained form the following places:
dnotify.d
https://github.com/Dav1dde/dnotify/blob/master/dnotify.d
License: Creative Commons Zro 1.0 Universal
see https://github.com/Dav1dde/dnotify/blob/master/LICENSE
notify.d
https://github.com/D-Programming-Deimos/libnotify/blob/master/deimos/notify/notify.d
License: GPL 2.1 or upwards, see file

309
src/notifications/dnotify.d Normal file
View file

@ -0,0 +1,309 @@
module dnotify;
private {
import std.string : toStringz;
import std.conv : to;
import std.traits : isPointer, isArray;
import std.variant : Variant;
import std.array : appender;
import deimos.notify.notify;
}
public import deimos.notify.notify : NOTIFY_EXPIRES_DEFAULT, NOTIFY_EXPIRES_NEVER,
NotifyUrgency;
version(NoPragma) {
} else {
pragma(lib, "notify");
pragma(lib, "gmodule");
pragma(lib, "glib-2.0");
}
extern (C) {
private void g_free(void* mem);
private void g_list_free(GList* glist);
}
version(NoGdk) {
} else {
version(NoPragma) {
} else {
pragma(lib, "gdk_pixbuf");
}
private:
extern (C) {
GdkPixbuf* gdk_pixbuf_new_from_file(const(char)* filename, GError **error);
}
}
class NotificationError : Exception {
string message;
GError* gerror;
this(GError* gerror) {
this.message = to!(string)(gerror.message);
this.gerror = gerror;
super(this.message);
}
this(string message) {
this.message = message;
super(message);
}
}
void init(in char[] name) {
notify_init(name.toStringz());
}
alias notify_is_initted is_initted;
alias notify_uninit uninit;
static this() {
init(__FILE__);
}
static ~this() {
uninit();
}
string get_app_name() {
return to!(string)(notify_get_app_name());
}
void set_app_name(in char[] app_name) {
notify_set_app_name(app_name.toStringz());
}
string[] get_server_caps() {
auto result = appender!(string[])();
GList* list = notify_get_server_caps();
if(list !is null) {
for(GList* c = list; c !is null; c = c.next) {
result.put(to!(string)(cast(char*)c.data));
g_free(c.data);
}
g_list_free(list);
}
return result.data;
}
struct ServerInfo {
string name;
string vendor;
string version_;
string spec_version;
}
ServerInfo get_server_info() {
char* name;
char* vendor;
char* version_;
char* spec_version;
notify_get_server_info(&name, &vendor, &version_, &spec_version);
scope(exit) {
g_free(name);
g_free(vendor);
g_free(version_);
g_free(spec_version);
}
return ServerInfo(to!string(name), to!string(vendor), to!string(version_), to!string(spec_version));
}
struct Action {
const(char[]) id;
const(char[]) label;
NotifyActionCallback callback;
void* user_ptr;
}
class Notification {
NotifyNotification* notify_notification;
const(char)[] summary;
const(char)[] body_;
const(char)[] icon;
bool closed = true;
private int _timeout = NOTIFY_EXPIRES_DEFAULT;
const(char)[] _category;
NotifyUrgency _urgency;
GdkPixbuf* _image;
Variant[const(char)[]] _hints;
const(char)[] _app_name;
Action[] _actions;
this(in char[] summary, in char[] body_, in char[] icon="")
in { assert(is_initted(), "call dnotify.init() before using Notification"); }
body {
this.summary = summary;
this.body_ = body_;
this.icon = icon;
notify_notification = notify_notification_new(summary.toStringz(), body_.toStringz(), icon.toStringz());
}
bool update(in char[] summary, in char[] body_, in char[] icon="") {
this.summary = summary;
this.body_ = body_;
this.icon = icon;
return notify_notification_update(notify_notification, summary.toStringz(), body_.toStringz(), icon.toStringz());
}
void show() {
GError* ge;
if(!notify_notification_show(notify_notification, &ge)) {
throw new NotificationError(ge);
}
}
@property int timeout() { return _timeout; }
@property void timeout(int timeout) {
this._timeout = timeout;
notify_notification_set_timeout(notify_notification, timeout);
}
@property const(char[]) category() { return _category; }
@property void category(in char[] category) {
this._category = category;
notify_notification_set_category(notify_notification, category.toStringz());
}
@property NotifyUrgency urgency() { return _urgency; }
@property void urgency(NotifyUrgency urgency) {
this._urgency = urgency;
notify_notification_set_urgency(notify_notification, urgency);
}
void set_image(GdkPixbuf* pixbuf) {
notify_notification_set_image_from_pixbuf(notify_notification, pixbuf);
//_image = pixbuf;
}
version(NoGdk) {
} else {
void set_image(in char[] filename) {
GError* ge;
// TODO: free pixbuf
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file(filename.toStringz(), &ge);
if(pixbuf is null) {
if(ge is null) {
throw new NotificationError("Unable to load file: " ~ filename.idup);
} else {
throw new NotificationError(ge);
}
}
assert(notify_notification !is null);
notify_notification_set_image_from_pixbuf(notify_notification, pixbuf); // TODO: fix segfault
//_image = pixbuf;
}
}
@property GdkPixbuf* image() { return _image; }
// using deprecated set_hint_* functions (GVariant is an opaque structure, which needs the glib)
void set_hint(T)(in char[] key, T value) {
static if(is(T == int)) {
notify_notification_set_hint_int32(notify_notification, key, value);
} else static if(is(T == uint)) {
notify_notification_set_hint_uint32(notify_notification, key, value);
} else static if(is(T == double)) {
notify_notification_set_hint_double(notify_notification, key, value);
} else static if(is(T : const(char)[])) {
notify_notification_set_hint_string(notify_notification, key, value.toStringz());
} else static if(is(T == ubyte)) {
notify_notification_set_hint_byte(notify_notification, key, value);
} else static if(is(T == ubyte[])) {
notify_notification_set_hint_byte_array(notify_notification, key, value.ptr, value.length);
} else {
static assert(false, "unsupported value for Notification.set_hint");
}
_hints[key] = Variant(value);
}
// unset hint?
Variant get_hint(in char[] key) {
return _hints[key];
}
@property const(char)[] app_name() { return _app_name; }
@property void app_name(in char[] name) {
this._app_name = app_name;
notify_notification_set_app_name(notify_notification, app_name.toStringz());
}
void add_action(T)(in char[] action, in char[] label, NotifyActionCallback callback, T user_data) {
static if(isPointer!T) {
void* user_ptr = cast(void*)user_data;
} else static if(isArray!T) {
void* user_ptr = cast(void*)user_data.ptr;
} else {
void* user_ptr = cast(void*)&user_data;
}
notify_notification_add_action(notify_notification, action.toStringz(), label.toStringz(),
callback, user_ptr, null);
_actions ~= Action(action, label, callback, user_ptr);
}
void add_action()(Action action) {
notify_notification_add_action(notify_notification, action.id.toStringz(), action.label.toStringz(),
action.callback, action.user_ptr, null);
_actions ~= action;
}
@property Action[] actions() { return _actions; }
void clear_actions() {
notify_notification_clear_actions(notify_notification);
}
void close() {
GError* ge;
if(!notify_notification_close(notify_notification, &ge)) {
throw new NotificationError(ge);
}
}
@property int closed_reason() {
return notify_notification_get_closed_reason(notify_notification);
}
}
version(TestMain) {
import std.stdio;
void main() {
writeln(get_app_name());
set_app_name("bla");
writeln(get_app_name());
writeln(get_server_caps());
writeln(get_server_info());
auto n = new Notification("foo", "bar", "notification-message-im");
n.timeout = 3;
n.show();
}
}

195
src/notifications/notify.d Normal file
View file

@ -0,0 +1,195 @@
/**
* Copyright (C) 2004-2006 Christian Hammond
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
module deimos.notify.notify;
enum NOTIFY_VERSION_MAJOR = 0;
enum NOTIFY_VERSION_MINOR = 7;
enum NOTIFY_VERSION_MICRO = 5;
template NOTIFY_CHECK_VERSION(int major, int minor, int micro) {
enum NOTIFY_CHECK_VERSION = ((NOTIFY_VERSION_MAJOR > major) ||
(NOTIFY_VERSION_MAJOR == major && NOTIFY_VERSION_MINOR > minor) ||
(NOTIFY_VERSION_MAJOR == major && NOTIFY_VERSION_MINOR == minor &&
NOTIFY_VERSION_MICRO >= micro));
}
alias ulong GType;
alias void function(void*) GFreeFunc;
struct GError {
uint domain;
int code;
char* message;
}
struct GList {
void* data;
GList* next;
GList* prev;
}
// dummies
struct GdkPixbuf {}
struct GObject {}
struct GObjectClass {}
struct GVariant {}
GType notify_urgency_get_type();
/**
* NOTIFY_EXPIRES_DEFAULT:
*
* The default expiration time on a notification.
*/
enum NOTIFY_EXPIRES_DEFAULT = -1;
/**
* NOTIFY_EXPIRES_NEVER:
*
* The notification never expires. It stays open until closed by the calling API
* or the user.
*/
enum NOTIFY_EXPIRES_NEVER = 0;
// #define NOTIFY_TYPE_NOTIFICATION (notify_notification_get_type ())
// #define NOTIFY_NOTIFICATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NOTIFY_TYPE_NOTIFICATION, NotifyNotification))
// #define NOTIFY_NOTIFICATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NOTIFY_TYPE_NOTIFICATION, NotifyNotificationClass))
// #define NOTIFY_IS_NOTIFICATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NOTIFY_TYPE_NOTIFICATION))
// #define NOTIFY_IS_NOTIFICATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NOTIFY_TYPE_NOTIFICATION))
// #define NOTIFY_NOTIFICATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NOTIFY_TYPE_NOTIFICATION, NotifyNotificationClass))
extern (C) {
struct NotifyNotificationPrivate;
struct NotifyNotification {
/*< private >*/
GObject parent_object;
NotifyNotificationPrivate *priv;
}
struct NotifyNotificationClass {
GObjectClass parent_class;
/* Signals */
void function(NotifyNotification *notification) closed;
}
/**
* NotifyUrgency:
* @NOTIFY_URGENCY_LOW: Low urgency. Used for unimportant notifications.
* @NOTIFY_URGENCY_NORMAL: Normal urgency. Used for most standard notifications.
* @NOTIFY_URGENCY_CRITICAL: Critical urgency. Used for very important notifications.
*
* The urgency level of the notification.
*/
enum NotifyUrgency {
NOTIFY_URGENCY_LOW,
NOTIFY_URGENCY_NORMAL,
NOTIFY_URGENCY_CRITICAL,
}
/**
* NotifyActionCallback:
* @notification:
* @action:
* @user_data:
*
* An action callback function.
*/
alias void function(NotifyNotification* notification, char* action, void* user_data) NotifyActionCallback;
GType notify_notification_get_type();
NotifyNotification* notify_notification_new(const(char)* summary, const(char)* body_, const(char)* icon);
bool notify_notification_update(NotifyNotification* notification, const(char)* summary, const(char)* body_, const(char)* icon);
bool notify_notification_show(NotifyNotification* notification, GError** error);
void notify_notification_set_timeout(NotifyNotification* notification, int timeout);
void notify_notification_set_category(NotifyNotification* notification, const(char)* category);
void notify_notification_set_urgency(NotifyNotification* notification, NotifyUrgency urgency);
void notify_notification_set_image_from_pixbuf(NotifyNotification* notification, GdkPixbuf* pixbuf);
void notify_notification_set_icon_from_pixbuf(NotifyNotification* notification, GdkPixbuf* icon);
void notify_notification_set_hint_int32(NotifyNotification* notification, const(char)* key, int value);
void notify_notification_set_hint_uint32(NotifyNotification* notification, const(char)* key, uint value);
void notify_notification_set_hint_double(NotifyNotification* notification, const(char)* key, double value);
void notify_notification_set_hint_string(NotifyNotification* notification, const(char)* key, const(char)* value);
void notify_notification_set_hint_byte(NotifyNotification* notification, const(char)* key, ubyte value);
void notify_notification_set_hint_byte_array(NotifyNotification* notification, const(char)* key, const(ubyte)* value, ulong len);
void notify_notification_set_hint(NotifyNotification* notification, const(char)* key, GVariant* value);
void notify_notification_set_app_name(NotifyNotification* notification, const(char)* app_name);
void notify_notification_clear_hints(NotifyNotification* notification);
void notify_notification_add_action(NotifyNotification* notification, const(char)* action, const(char)* label,
NotifyActionCallback callback, void* user_data, GFreeFunc free_func);
void notify_notification_clear_actions(NotifyNotification* notification);
bool notify_notification_close(NotifyNotification* notification, GError** error);
int notify_notification_get_closed_reason(const NotifyNotification* notification);
bool notify_init(const(char)* app_name);
void notify_uninit();
bool notify_is_initted();
const(char)* notify_get_app_name();
void notify_set_app_name(const(char)* app_name);
GList *notify_get_server_caps();
bool notify_get_server_info(char** ret_name, char** ret_vendor, char** ret_version, char** ret_spec_version);
}
version(MainTest) {
import std.string;
void main() {
notify_init("test".toStringz());
auto n = notify_notification_new("summary".toStringz(), "body".toStringz(), "none".toStringz());
GError* ge;
notify_notification_show(n, &ge);
scope(success) notify_uninit();
}
}

View file

@ -545,7 +545,8 @@ final class OneDriveApi
http.perform();
} catch (CurlException e) {
// Potentially Timeout was reached on handle error
log.error("\nAccess to the Microsoft OneDrive service timed out - Internet connectivity issue?\n");
// we issue warning/error in the catch routines so no need to warn here
// log.error("\nAccess to the Microsoft OneDrive service timed out - Internet connectivity issue?\n");
throw e;
}