mirror of
https://github.com/abraunegg/onedrive
synced 2024-05-02 14:12:52 +02:00
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:
parent
487cfab8d1
commit
cc6cbf5ac7
10
Makefile
10
Makefile
|
@ -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:
|
||||
|
|
49
README.md
49
README.md
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
45
src/log.d
45
src/log.d
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
30
src/main.d
30
src/main.d
|
@ -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
10
src/notifications/README
Normal 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
309
src/notifications/dnotify.d
Normal 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
195
src/notifications/notify.d
Normal 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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue