mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
platform: system notifications reworked
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1,52 +0,0 @@
|
||||
#include "com_intellij_ui_LibNotifyWrapper.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
/*
|
||||
* Class: com_intellij_ui_LibNotifyWrapper
|
||||
* Method: showNotification
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_intellij_ui_LibNotifyWrapper_showNotification
|
||||
(JNIEnv * jEnv, jclass c, jstring jTitle, jstring jDescription, jstring jLogoPath) {
|
||||
|
||||
void *handle;
|
||||
gboolean (*notify_init_func)(const char *app_name);
|
||||
void (*notify_uninit_func)();
|
||||
NotifyNotification* (*notify_notification_new_func) (const char *summary,
|
||||
const char *body,
|
||||
const char *icon);
|
||||
gboolean (*notify_notification_show_func) (NotifyNotification *notification,
|
||||
GError **error);
|
||||
char *error;
|
||||
|
||||
dlerror();
|
||||
|
||||
handle = dlopen("libnotify.so", RTLD_LAZY);
|
||||
|
||||
if ((error = dlerror()) != NULL)
|
||||
{
|
||||
(*jEnv)->ThrowNew(jEnv, (*jEnv)->FindClass(jEnv, "java/lang/UnsatisfiedLinkError"), error);
|
||||
return;
|
||||
}
|
||||
|
||||
dlerror();
|
||||
|
||||
*(void **) (¬ify_init_func) = dlsym(handle, "notify_init");
|
||||
*(void **) (¬ify_uninit_func) = dlsym(handle, "notify_init");
|
||||
*(void **) (¬ify_notification_new_func) = dlsym(handle, "notify_notification_new");
|
||||
*(void **) (¬ify_notification_show_func) = dlsym(handle, "notify_notification_show");
|
||||
|
||||
(*notify_init_func) ("JetBrains");
|
||||
|
||||
const char *title = (*jEnv)->GetStringUTFChars(jEnv, jTitle, 0);
|
||||
const char *description = (*jEnv)->GetStringUTFChars(jEnv, jDescription, 0);
|
||||
const char *logoPath = (*jEnv)->GetStringUTFChars(jEnv, jLogoPath, 0);
|
||||
NotifyNotification * notification = (*notify_notification_new_func) (title, description, logoPath);
|
||||
(*notify_notification_show_func) (notification, NULL);
|
||||
(*notify_uninit_func)();
|
||||
(*jEnv)->ReleaseStringUTFChars(jEnv, jTitle, title);
|
||||
(*jEnv)->ReleaseStringUTFChars(jEnv, jDescription, description);
|
||||
(*jEnv)->ReleaseStringUTFChars(jEnv, jLogoPath, logoPath);
|
||||
|
||||
dlclose(handle);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
#include <libnotify/notify.h>
|
||||
/* Header for class com_intellij_ui_LibNotifyWrapper */
|
||||
|
||||
#ifndef _Included_com_intellij_ui_LibNotifyWrapper
|
||||
#define _Included_com_intellij_ui_LibNotifyWrapper
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_intellij_ui_LibNotifyWrapper
|
||||
* Method: showNotification
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_intellij_ui_LibNotifyWrapper_showNotification
|
||||
(JNIEnv *, jclass, jstring, jstring, jstring);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -27,56 +27,45 @@ import java.util.TreeSet;
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
class GrowlNotifications implements MacNotifications {
|
||||
class GrowlNotifications implements SystemNotificationsImpl.Notifier {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ui.GrowlNotifications");
|
||||
|
||||
private static GrowlNotifications ourNotifications;
|
||||
private final Set<String> myNotifications = new TreeSet<String>();
|
||||
private Growl myGrowl;
|
||||
|
||||
public GrowlNotifications() {
|
||||
this(ApplicationNamesInfo.getInstance().getFullProductName());
|
||||
}
|
||||
|
||||
GrowlNotifications(String fullProductName) {
|
||||
myGrowl = new Growl(fullProductName);
|
||||
register();
|
||||
}
|
||||
|
||||
private String[] getAllNotifications() {
|
||||
return ArrayUtil.toStringArray(myNotifications);
|
||||
}
|
||||
|
||||
public static synchronized GrowlNotifications getNotifications() {
|
||||
public static synchronized GrowlNotifications getInstance() {
|
||||
if (ourNotifications == null) {
|
||||
ourNotifications = new GrowlNotifications();
|
||||
}
|
||||
|
||||
return ourNotifications;
|
||||
}
|
||||
|
||||
public void notify(Set<String> allNotifications, @NotNull String notificationName, String title, String description) {
|
||||
if (!myNotifications.equals(allNotifications)) {
|
||||
myNotifications.addAll(allNotifications);
|
||||
register();
|
||||
}
|
||||
private final Growl myGrowl;
|
||||
private final Set<String> myNotifications;
|
||||
|
||||
try {
|
||||
myGrowl.notifyGrowlOf(notificationName, title, description);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
private GrowlNotifications() {
|
||||
myGrowl = new Growl(ApplicationNamesInfo.getInstance().getFullProductName());
|
||||
myNotifications = new TreeSet<String>();
|
||||
register();
|
||||
}
|
||||
|
||||
private void register() {
|
||||
myGrowl.setAllowedNotifications(getAllNotifications());
|
||||
try {
|
||||
myGrowl.setDefaultNotifications(getAllNotifications());
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
myGrowl.setAllowedNotifications(ArrayUtil.toStringArray(myNotifications));
|
||||
myGrowl.setDefaultNotifications(ArrayUtil.toStringArray(myNotifications));
|
||||
myGrowl.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(@NotNull Set<String> allNames, @NotNull String name, @NotNull String title, @NotNull String description) {
|
||||
try {
|
||||
if (!myNotifications.equals(allNames)) {
|
||||
myNotifications.addAll(allNames);
|
||||
register();
|
||||
}
|
||||
|
||||
myGrowl.notifyGrowlOf(name, title, description);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,53 +15,63 @@
|
||||
*/
|
||||
package com.intellij.ui;
|
||||
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationGroup;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.notification.Notifications;
|
||||
import com.intellij.ide.AppLifecycleListener;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.util.lang.UrlClassLoader;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Pointer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Denis Fokin
|
||||
*/
|
||||
public class LibNotifyWrapper {
|
||||
class LibNotifyWrapper implements SystemNotificationsImpl.Notifier {
|
||||
private static LibNotifyWrapper ourInstance;
|
||||
|
||||
private final static String message = "Looks like you have run 32-bit Java on a 64-bit version of OS " +
|
||||
"or just have not installed appropriate libnotify.so library";
|
||||
|
||||
private static boolean available = true;
|
||||
|
||||
static{
|
||||
UrlClassLoader.loadPlatformLibrary("notifywrapper");
|
||||
}
|
||||
|
||||
native private static void showNotification(final String title, final String description, final String iconPath);
|
||||
|
||||
public static void show(final String title, final String description, final String iconPath) {
|
||||
if (! available) return;
|
||||
try {
|
||||
showNotification(title, description, iconPath);
|
||||
} catch (UnsatisfiedLinkError ule) {
|
||||
available = false;
|
||||
NotificationGroup.balloonGroup("Linux configuration messages");
|
||||
Notifications.Bus.notify(
|
||||
new Notification("Linux configuration messages",
|
||||
"Notification library has not been installed",
|
||||
message, NotificationType.INFORMATION)
|
||||
);
|
||||
public static synchronized LibNotifyWrapper getInstance() {
|
||||
if (ourInstance == null) {
|
||||
ourInstance = new LibNotifyWrapper();
|
||||
}
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a libnotify notification with an icon from the ide bin directory.
|
||||
* If there is no such icon a default information icon is shown.
|
||||
* @param title notification title
|
||||
* @param description notification description
|
||||
*/
|
||||
public static void showWithAppIcon(final String title, final String description) {
|
||||
String iconPath = AppUIUtil.findIcon(PathManager.getBinPath());
|
||||
show(title, description, (iconPath == null) ? "dialog-information" : iconPath);
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private interface LibNotify extends Library {
|
||||
int notify_init(String appName);
|
||||
void notify_uninit();
|
||||
Pointer notify_notification_new(String summary, String body, String icon);
|
||||
int notify_notification_show(Pointer notification, Pointer error);
|
||||
}
|
||||
|
||||
private final LibNotify myLibNotify;
|
||||
|
||||
private LibNotifyWrapper() {
|
||||
myLibNotify = (LibNotify)Native.loadLibrary("notify", LibNotify.class);
|
||||
|
||||
String appName = ApplicationNamesInfo.getInstance().getProductName();
|
||||
if (myLibNotify.notify_init(appName) == 0) {
|
||||
throw new IllegalStateException("notify_init failed");
|
||||
}
|
||||
|
||||
MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect();
|
||||
connection.subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() {
|
||||
@Override
|
||||
public void appClosing() {
|
||||
myLibNotify.notify_uninit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(@NotNull Set<String> allNames, @NotNull String name, @NotNull String title, @NotNull String description) {
|
||||
String icon = AppUIUtil.findIcon(PathManager.getBinPath());
|
||||
if (icon == null) icon = "dialog-information";
|
||||
Pointer notification = myLibNotify.notify_notification_new(title, description, icon);
|
||||
myLibNotify.notify_notification_show(notification, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ui;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Dennis.Ushakov
|
||||
*/
|
||||
public interface MacNotifications {
|
||||
void notify(Set<String> allNotifications, @NotNull String notificationName, String title, String description);
|
||||
}
|
||||
@@ -33,19 +33,23 @@ import static com.intellij.ui.mac.foundation.Foundation.nsString;
|
||||
/**
|
||||
* @author Dennis.Ushakov
|
||||
*/
|
||||
public class MountainLionNotifications implements MacNotifications {
|
||||
private static MountainLionNotifications ourNotifications;
|
||||
class MountainLionNotifications implements SystemNotificationsImpl.Notifier {
|
||||
private static MountainLionNotifications ourInstance;
|
||||
|
||||
public MountainLionNotifications() {
|
||||
public static synchronized MountainLionNotifications getInstance() {
|
||||
if (ourInstance == null) {
|
||||
ourInstance = new MountainLionNotifications();
|
||||
}
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
private MountainLionNotifications() {
|
||||
final MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect();
|
||||
connection.subscribe(ApplicationActivationListener.TOPIC, new ApplicationActivationListener() {
|
||||
connection.subscribe(ApplicationActivationListener.TOPIC, new ApplicationActivationListener.Adapter() {
|
||||
@Override
|
||||
public void applicationActivated(IdeFrame ideFrame) {
|
||||
cleanupDeliveredNotifications();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applicationDeactivated(IdeFrame ideFrame) {}
|
||||
});
|
||||
connection.subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() {
|
||||
@Override
|
||||
@@ -55,24 +59,16 @@ public class MountainLionNotifications implements MacNotifications {
|
||||
});
|
||||
}
|
||||
|
||||
public static synchronized MacNotifications getNotifications() {
|
||||
if (ourNotifications == null) {
|
||||
ourNotifications = new MountainLionNotifications();
|
||||
}
|
||||
|
||||
return ourNotifications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(Set<String> allNotifications, @NotNull String notificationName, String title, String description) {
|
||||
public void notify(@NotNull Set<String> allNames, @NotNull String name, @NotNull String title, @NotNull String description) {
|
||||
final ID notification = invoke(Foundation.getObjcClass("NSUserNotification"), "new");
|
||||
invoke(notification, "setTitle:", nsString(StringUtil.stripHtml(title == null ? "" : title, true).replace("%", "%%")));
|
||||
invoke(notification, "setInformativeText:", nsString(StringUtil.stripHtml(description == null ? "" : description, true).replace("%", "%%")));
|
||||
invoke(notification, "setTitle:", nsString(StringUtil.stripHtml(title, true).replace("%", "%%")));
|
||||
invoke(notification, "setInformativeText:", nsString(StringUtil.stripHtml(description, true).replace("%", "%%")));
|
||||
final ID center = invoke(Foundation.getObjcClass("NSUserNotificationCenter"), "defaultUserNotificationCenter");
|
||||
invoke(center, "deliverNotification:", notification);
|
||||
}
|
||||
|
||||
public static void cleanupDeliveredNotifications() {
|
||||
private static void cleanupDeliveredNotifications() {
|
||||
final ID center = invoke(Foundation.getObjcClass("NSUserNotificationCenter"), "defaultUserNotificationCenter");
|
||||
invoke(center, "removeAllDeliveredNotifications");
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -33,65 +34,58 @@ import java.util.Set;
|
||||
@State(
|
||||
name = "SystemNotifications",
|
||||
storages = {
|
||||
@Storage(
|
||||
file = StoragePathMacros.APP_CONFIG + "/other.xml"
|
||||
)}
|
||||
@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml")
|
||||
}
|
||||
)
|
||||
public class SystemNotificationsImpl extends SystemNotifications implements PersistentStateComponent<SystemNotificationsImpl.State> {
|
||||
public static class State {
|
||||
public Set<String> NOTIFICATIONS = new HashSet<String>();
|
||||
}
|
||||
|
||||
interface Notifier {
|
||||
void notify(@NotNull Set<String> allNames, @NotNull String name, @NotNull String title, @NotNull String description);
|
||||
}
|
||||
|
||||
private final Notifier myNotifier = getPlatformNotifier();
|
||||
private State myState = new State();
|
||||
private boolean myGrowlDisabled = false;
|
||||
|
||||
public void notify(@NotNull String notificationName, @NotNull String title, @NotNull String text) {
|
||||
if (!areNotificationsEnabled() || ApplicationManager.getApplication().isActive()) return;
|
||||
|
||||
if (SystemInfo.isLinux && Registry.is("ide.linux.gtk.notifications.enabled") ) {
|
||||
LibNotifyWrapper.showWithAppIcon(title, text);
|
||||
return;
|
||||
}
|
||||
|
||||
final MacNotifications notifications;
|
||||
try {
|
||||
notifications = getMacNotifications();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
myGrowlDisabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
myState.NOTIFICATIONS.add(notificationName);
|
||||
notifications.notify(myState.NOTIFICATIONS, notificationName, title, text);
|
||||
}
|
||||
|
||||
private static MacNotifications getMacNotifications() {
|
||||
return SystemInfo.isMacOSMountainLion && Registry.is("ide.mac.mountain.lion.notifications.enabled") ?
|
||||
MountainLionNotifications.getNotifications() : GrowlNotifications.getNotifications();
|
||||
}
|
||||
|
||||
private boolean areNotificationsEnabled() {
|
||||
boolean enabled = false;
|
||||
|
||||
if (SystemInfo.isMac) {
|
||||
enabled = !(myGrowlDisabled || "true".equalsIgnoreCase(System.getProperty("growl.disable")));
|
||||
if (!enabled) {
|
||||
enabled = SystemInfo.isMacOSMountainLion && Registry.is("ide.mac.mountain.lion.notifications.enabled");
|
||||
}
|
||||
} else {
|
||||
enabled = SystemInfo.isLinux && Registry.is("ide.linux.gtk.notifications.enabled");
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(final State state) {
|
||||
myState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(@NotNull String notificationName, @NotNull String title, @NotNull String text) {
|
||||
if (myNotifier != null && !ApplicationManager.getApplication().isActive()) {
|
||||
myState.NOTIFICATIONS.add(notificationName);
|
||||
myNotifier.notify(myState.NOTIFICATIONS, notificationName, title, text);
|
||||
}
|
||||
}
|
||||
|
||||
public static class State {
|
||||
public Set<String> NOTIFICATIONS = new HashSet<String>();
|
||||
private static Notifier getPlatformNotifier() {
|
||||
try {
|
||||
if (SystemInfo.isMac) {
|
||||
if (SystemInfo.isMacOSMountainLion && Registry.is("ide.mac.mountain.lion.notifications.enabled")) {
|
||||
return MountainLionNotifications.getInstance();
|
||||
}
|
||||
if (!Boolean.getBoolean("growl.disable")) {
|
||||
return GrowlNotifications.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
if (SystemInfo.isXWindow && Registry.is("ide.libnotify.enabled") ) {
|
||||
return LibNotifyWrapper.getInstance();
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
Logger.getInstance(SystemNotifications.class).error(t);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,8 +354,9 @@ bigger.font.in.project.view.description=Increases font size in Project View
|
||||
darcula.use.native.fonts.on.linux=true
|
||||
darcula.use.native.fonts.on.linux.description=If false, uses DejaVu Sans 13pt
|
||||
idea.4.5.laf.enabled=false
|
||||
ide.linux.gtk.notifications.enabled=true
|
||||
ide.linux.gtk.notifications.enabled.description=Enables GTK notifications on linux
|
||||
ide.libnotify.enabled=true
|
||||
# suppress inspection "UnusedProperty"
|
||||
ide.libnotify.enabled.description=Enables notifications via LibNotify
|
||||
cvs.roots.refresh.uses.vfs=true
|
||||
cvs.roots.refresh.uses.vfs.description=Should CVS roots refresh after update use VFS
|
||||
editor.wrap.collapsed.region.at.line.start=false
|
||||
|
||||
Reference in New Issue
Block a user