diff --git a/README.md b/README.md
index 67fd911..5799c67 100644
--- a/README.md
+++ b/README.md
@@ -35,3 +35,12 @@ The app uses an embedded Nitrine database for storing the current sync state of
- `~/Library/Application Support/Goobox` for macOS
The `list-db.bat` script can be used to dump the content of the database. This might be useful for debugging.
+
+### Overlay icons on Windows
+
+Setting up the overlay icons on Windows required the following steps:
+
+1. Open a Command Prompt as Administrator
+1. Execute the `register-dlls.bat` file
+1. Restart Windows
+1. Run the app as usual
diff --git a/pom.xml b/pom.xml
index f5b390e..abe197d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,6 +64,11 @@
libstorj-java
0.4
+
+ com.liferay
+ com.liferay.nativity
+ 1.0.5
+
org.dizitart
nitrite
diff --git a/src/main/java/io/goobox/sync/storj/App.java b/src/main/java/io/goobox/sync/storj/App.java
index 2068585..9ce888d 100644
--- a/src/main/java/io/goobox/sync/storj/App.java
+++ b/src/main/java/io/goobox/sync/storj/App.java
@@ -21,9 +21,17 @@
import java.nio.file.Path;
import java.util.concurrent.CountDownLatch;
+import com.liferay.nativity.control.NativityControl;
+import com.liferay.nativity.control.NativityControlUtil;
+import com.liferay.nativity.modules.fileicon.FileIconControl;
+import com.liferay.nativity.modules.fileicon.FileIconControlCallback;
+import com.liferay.nativity.modules.fileicon.FileIconControlUtil;
+import com.liferay.nativity.util.OSDetector;
+
import io.goobox.sync.common.Utils;
import io.goobox.sync.common.systemtray.ShutdownListener;
import io.goobox.sync.common.systemtray.SystemTrayHelper;
+import io.goobox.sync.storj.overlay.OverlayHelper;
import io.storj.libstorj.Bucket;
import io.storj.libstorj.CreateBucketCallback;
import io.storj.libstorj.GetBucketsCallback;
@@ -42,6 +50,49 @@ public class App implements ShutdownListener {
public static void main(String[] args) {
instance = new App();
instance.init();
+
+ NativityControl nativityControl = NativityControlUtil.getNativityControl();
+ nativityControl.connect();
+
+ // Setting filter folders is required for Mac's Finder Sync plugin
+ // nativityControl.setFilterFolder(Utils.getSyncDir().toString());
+
+ /* File Icons */
+
+ int testIconId = 1;
+
+ // FileIconControlCallback used by Windows and Mac
+ FileIconControlCallback fileIconControlCallback = new FileIconControlCallback() {
+ @Override
+ public int getIconForFile(String path) {
+ return 1; // testIconId;
+ }
+ };
+
+ FileIconControl fileIconControl = FileIconControlUtil.getFileIconControl(nativityControl,
+ fileIconControlCallback);
+
+ fileIconControl.enableFileIcons();
+
+ String testFilePath = Utils.getSyncDir().toString();
+
+ if (OSDetector.isWindows()) {
+ // This id is determined when building the DLL
+ testIconId = 1;
+ } else if (OSDetector.isMinimumAppleVersion(OSDetector.MAC_YOSEMITE_10_10)) {
+ // Used by Mac Finder Sync. This unique id can be set at runtime.
+ testIconId = 1;
+
+ fileIconControl.registerIconWithId("/tmp/goobox.icns",
+ "test label", "" + testIconId);
+ } else if (OSDetector.isLinux()) {
+ // Used by Mac Injector and Linux
+ testIconId = fileIconControl.registerIcon("/tmp/git-clean.png");
+ }
+
+ // FileIconControl.setFileIcon() method only used by Linux
+ fileIconControl.setFileIcon(testFilePath, testIconId);
+ nativityControl.disconnect();
}
public static App getInstance() {
@@ -97,6 +148,7 @@ private void init() {
@Override
public void shutdown() {
// TODO graceful shutdown
+ OverlayHelper.getInstance().shutdown();
System.exit(0);
}
diff --git a/src/main/java/io/goobox/sync/storj/CheckStateTask.java b/src/main/java/io/goobox/sync/storj/CheckStateTask.java
index 1293502..4125348 100644
--- a/src/main/java/io/goobox/sync/storj/CheckStateTask.java
+++ b/src/main/java/io/goobox/sync/storj/CheckStateTask.java
@@ -31,6 +31,7 @@
import io.goobox.sync.storj.db.DB;
import io.goobox.sync.storj.db.SyncFile;
import io.goobox.sync.storj.db.SyncState;
+import io.goobox.sync.storj.overlay.OverlayHelper;
import io.storj.libstorj.Bucket;
import io.storj.libstorj.File;
import io.storj.libstorj.ListFilesCallback;
@@ -56,6 +57,7 @@ public void run() {
System.out.println("Checking for changes...");
SystemTrayHelper.setSynchronizing();
+ OverlayHelper.getInstance().setSynchronizing();
Storj.getInstance().listFiles(gooboxBucket, new ListFilesCallback() {
@Override
@@ -68,6 +70,7 @@ public void onFilesReceived(File[] files) {
// Sleep some time to avoid overloading the bridge
tasks.add(new SleepTask());
SystemTrayHelper.setIdle();
+ OverlayHelper.getInstance().setOK();
}
// Add itself to the queueAdd itself to the queue
tasks.add(CheckStateTask.this);
diff --git a/src/main/java/io/goobox/sync/storj/overlay/OverlayHelper.java b/src/main/java/io/goobox/sync/storj/overlay/OverlayHelper.java
new file mode 100644
index 0000000..fb160a3
--- /dev/null
+++ b/src/main/java/io/goobox/sync/storj/overlay/OverlayHelper.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 Kaloyan Raev
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package io.goobox.sync.storj.overlay;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.attribute.DosFileAttributeView;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.liferay.nativity.control.NativityControl;
+import com.liferay.nativity.control.NativityControlUtil;
+import com.liferay.nativity.modules.contextmenu.ContextMenuControlCallback;
+import com.liferay.nativity.modules.contextmenu.ContextMenuControlUtil;
+import com.liferay.nativity.modules.contextmenu.model.ContextMenuAction;
+import com.liferay.nativity.modules.contextmenu.model.ContextMenuItem;
+import com.liferay.nativity.modules.fileicon.FileIconControl;
+import com.liferay.nativity.modules.fileicon.FileIconControlCallback;
+import com.liferay.nativity.modules.fileicon.FileIconControlUtil;
+import com.liferay.nativity.util.OSDetector;
+
+import io.goobox.sync.common.Utils;
+
+public class OverlayHelper {
+
+ private NativityControl nativityControl;
+ private FileIconControl fileIconControl;
+
+ private int stateIconId = 0;
+
+ private static OverlayHelper instance;
+
+ public static OverlayHelper getInstance() {
+ if (instance == null) {
+ instance = new OverlayHelper();
+ }
+ return instance;
+ }
+
+ public OverlayHelper() {
+ init();
+ }
+
+ public void setOK() {
+ if (!OSDetector.isWindows()) {
+ return;
+ }
+
+ stateIconId = 1;
+ refresh();
+ }
+
+ public void setSynchronizing() {
+ if (!OSDetector.isWindows()) {
+ return;
+ }
+
+ stateIconId = 2;
+ refresh();
+ }
+
+ public void shutdown() {
+ if (!OSDetector.isWindows()) {
+ return;
+ }
+
+ stateIconId = 0;
+ refresh();
+ nativityControl.disconnect();
+ }
+
+ private void refresh() {
+ fileIconControl.refreshIcons(new String[] { Utils.getSyncDir().toString() });
+ }
+
+ private void init() {
+ if (!OSDetector.isWindows()) {
+ return;
+ }
+
+ nativityControl = NativityControlUtil.getNativityControl();
+ nativityControl.connect();
+
+ // Setting filter folders is required for Mac's Finder Sync plugin
+ nativityControl.setFilterFolder(Utils.getSyncDir().toString());
+
+ DosFileAttributeView attr = Files.getFileAttributeView(Utils.getSyncDir(), DosFileAttributeView.class);
+ try {
+ attr.setSystem(true);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ // FileIconControlCallback used by Windows and Mac
+ FileIconControlCallback fileIconControlCallback = new FileIconControlCallback() {
+ @Override
+ public int getIconForFile(String path) {
+ if (Utils.getSyncDir().toString().equals(path)) {
+ return stateIconId;
+ }
+ return 0;
+ }
+ };
+
+ fileIconControl = FileIconControlUtil.getFileIconControl(nativityControl, fileIconControlCallback);
+
+ fileIconControl.enableFileIcons();
+
+ /* Context Menus */
+
+ ContextMenuControlCallback contextMenuControlCallback = new ContextMenuControlCallback() {
+ @Override
+ public List getContextMenuItems(String[] paths) {
+ ContextMenuItem contextMenuItem = new ContextMenuItem("Goobox");
+
+ ContextMenuAction contextMenuAction = new ContextMenuAction() {
+ @Override
+ public void onSelection(String[] paths) {
+ System.out.println("Context menu selection: " + String.join("; ", paths));
+ }
+ };
+
+ contextMenuItem.setContextMenuAction(contextMenuAction);
+
+ List contextMenuItems = new ArrayList();
+ contextMenuItems.add(contextMenuItem);
+
+ // Mac Finder Sync will only show the parent level of context menus
+ return contextMenuItems;
+ }
+ };
+
+ ContextMenuControlUtil.getContextMenuControl(nativityControl, contextMenuControlCallback);
+ }
+
+}