mirror of
https://github.com/moparisthebest/FireTray
synced 2024-12-22 05:48:49 -05:00
IM icon blinking when private message or cited in channel
This commit is contained in:
parent
866bbc1a2e
commit
9f46ef6343
@ -29,8 +29,9 @@ if ("undefined" == typeof(firetray)) {
|
||||
firetray.Handler = {
|
||||
|
||||
initialized: false,
|
||||
inMailApp: false,
|
||||
inBrowserApp: false,
|
||||
inMailApp: false,
|
||||
isIMEnabled: false,
|
||||
appStarted: false,
|
||||
windows: {},
|
||||
windowsCount: 0,
|
||||
@ -200,6 +201,7 @@ firetray.Handler = {
|
||||
showWindow: function(winId) {},
|
||||
showHideAllWindows: function() {},
|
||||
activateLastWindow: function(gtkStatusIcon, gdkEvent, userData) {},
|
||||
findActiveWindow: function() {},
|
||||
|
||||
showAllWindows: function() {
|
||||
F.LOG("showAllWindows");
|
||||
|
@ -14,6 +14,7 @@ Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm");
|
||||
firetray.InstantMessaging = {
|
||||
initialized: false,
|
||||
observedTopics: {},
|
||||
acknowledgeOnFocus: {},
|
||||
|
||||
init: function() {
|
||||
if (this.initialized) {
|
||||
@ -25,8 +26,8 @@ firetray.InstantMessaging = {
|
||||
firetray.Utils.addObservers(firetray.InstantMessaging, [
|
||||
// "*" // debugging
|
||||
"account-connected", "account-disconnected", "idle-time-changed",
|
||||
"new-directed-incoming-message", "new-text", "new-ui-conversation",
|
||||
"status-changed", "unread-im-count-changed", "visited-status-resolution"
|
||||
"new-directed-incoming-message", "status-changed",
|
||||
"unread-im-count-changed"
|
||||
]);
|
||||
firetray.IMStatusIcon.init();
|
||||
|
||||
@ -50,14 +51,29 @@ firetray.InstantMessaging = {
|
||||
case "account-disconnected":
|
||||
case "idle-time-changed":
|
||||
case "status-changed":
|
||||
// case "visited-status-resolution":
|
||||
this.updateIcon();
|
||||
break;
|
||||
|
||||
case "unread-im-count-changed":
|
||||
case "new-directed-incoming-message": // when PM or cited in channel
|
||||
let conv = subject.QueryInterface(Ci.prplIMessage).conversation;
|
||||
F.LOG("conversation name="+conv.name); // normalizedName shouldn't be necessary
|
||||
|
||||
let convIsActiveTabInActiveWin = this.isConvActiveTabInActiveWindow(conv);
|
||||
F.LOG("convIsActiveTabInActiveWin="+convIsActiveTabInActiveWin);
|
||||
let [unreadTargettedCount, unreadTotalCount] = this.countUnreadMessages();
|
||||
F.LOG("unreadTotalCount="+unreadTotalCount);
|
||||
if (!convIsActiveTabInActiveWin) { // don't blink when conv tab already on top
|
||||
this.acknowledgeOnFocus.must = true;
|
||||
this.acknowledgeOnFocus.conv = conv;
|
||||
firetray.IMStatusIcon.setIconBlinking(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case "new-directed-incoming-message": // when PM or cited in channel: new-directed-incoming-message: [xpconnect wrapped (nsISupports, nsIClassInfo, prplIMessage)] null
|
||||
case "unread-im-count-changed":
|
||||
let unreadMsgCount = data;
|
||||
if (unreadMsgCount == 0)
|
||||
this.stopIconBlinkingMaybe();
|
||||
// FIXME: setToolTip
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -65,6 +81,48 @@ firetray.InstantMessaging = {
|
||||
}
|
||||
},
|
||||
|
||||
stopIconBlinkingMaybe: function() {
|
||||
F.WARN("acknowledgeOnFocus.must="+this.acknowledgeOnFocus.must);
|
||||
let convIsActiveTabInActiveWin = this.isConvActiveTabInActiveWindow(
|
||||
this.acknowledgeOnFocus.conv);
|
||||
|
||||
if (this.acknowledgeOnFocus.must && convIsActiveTabInActiveWin) {
|
||||
firetray.IMStatusIcon.setIconBlinking(false);
|
||||
this.acknowledgeOnFocus.must = false;
|
||||
}
|
||||
},
|
||||
|
||||
isConvActiveTabInActiveWindow: function(conv) {
|
||||
let activeWin = firetray.Handler.findActiveWindow(),
|
||||
activeChatTab = null;
|
||||
if (!activeWin) return false;
|
||||
|
||||
activeChatTab = this.findActiveChatTab(activeWin);
|
||||
let convNameRegex = new RegExp(" - "+conv.name+"$");
|
||||
return activeChatTab ? convNameRegex.test(activeChatTab.title) : false;
|
||||
},
|
||||
|
||||
findActiveChatTab: function(xid) {
|
||||
let win = firetray.Handler.windows[xid].chromeWin;
|
||||
let tabmail = win.document.getElementById("tabmail");
|
||||
let chatTabs = tabmail.tabModes.chat.tabs;
|
||||
for each (let tab in chatTabs)
|
||||
if (tab.tabNode.selected) return tab;
|
||||
return null;
|
||||
},
|
||||
|
||||
// lifted from chat-messenger-overlay.js
|
||||
countUnreadMessages: function() {
|
||||
let convs = Services.conversations.getUIConversations();
|
||||
let unreadTargettedCount = 0;
|
||||
let unreadTotalCount = 0;
|
||||
for each (let conv in convs) {
|
||||
unreadTargettedCount += conv.unreadTargetedMessageCount;
|
||||
unreadTotalCount += conv.unreadIncomingMessageCount;
|
||||
}
|
||||
return [unreadTargettedCount, unreadTotalCount];
|
||||
},
|
||||
|
||||
updateIcon: function() {
|
||||
let userStatus = Services.core.globalUserStatus.statusType;
|
||||
F.LOG("IM status="+userStatus);
|
||||
|
@ -43,8 +43,12 @@ firetray.Messaging = {
|
||||
MailServices.mailSession.AddFolderListener(that.mailSessionListener,
|
||||
that.mailSessionListener.notificationFlags);
|
||||
|
||||
if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount())
|
||||
// FIXME: add im-icon pref
|
||||
// FIXME: watch out account-added !!
|
||||
if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount()) {
|
||||
firetray.InstantMessaging.init();
|
||||
firetray.Handler.isIMEnabled = true;
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
},
|
||||
@ -283,7 +287,7 @@ firetray.Messaging = {
|
||||
let rootFolder = accountServer.rootFolder; // nsIMsgFolder
|
||||
if (rootFolder.hasSubFolders) {
|
||||
let subFolders = rootFolder.subFolders;
|
||||
while(subFolders.hasMoreElements()) {
|
||||
while (subFolders.hasMoreElements()) {
|
||||
let folder = subFolders.getNext().QueryInterface(Ci.nsIMsgFolder);
|
||||
if (!(folder.flags & excludedFoldersFlags)) {
|
||||
msgCount = folderCountFunction(folder, msgCount);
|
||||
|
@ -237,6 +237,12 @@ function gdk_defines(lib) {
|
||||
{ "x_root": gobject.gdouble },
|
||||
{ "y_root": gobject.gdouble }
|
||||
]);
|
||||
this.GdkEventFocus = ctypes.StructType("GdkEventFocus", [
|
||||
{ "type": this.GdkEventType },
|
||||
{ "window": this.GdkWindow.ptr },
|
||||
{ "send_event": gobject.gint8 },
|
||||
{ "in": gobject.gint16 },
|
||||
]);
|
||||
|
||||
this.GdkFilterFunc_t = ctypes.FunctionType(
|
||||
ctypes.default_abi, this.GdkFilterReturn,
|
||||
|
@ -89,6 +89,7 @@ function gobject_defines(lib) {
|
||||
this.guint16 = ctypes.uint16_t;
|
||||
this.gint = ctypes.int;
|
||||
this.gint8 = ctypes.int8_t;
|
||||
this.gint16 = ctypes.int16_t;
|
||||
this.gchar = ctypes.char;
|
||||
this.guchar = ctypes.unsigned_char;
|
||||
this.gboolean = this.gint;
|
||||
|
@ -74,6 +74,10 @@ function gtk_defines(lib) {
|
||||
this.GCallbackWindowStateEvent_t = ctypes.FunctionType(
|
||||
ctypes.default_abi, gobject.gboolean,
|
||||
[this.GtkWidget.ptr, gdk.GdkEventWindowState.ptr, gobject.gpointer]).ptr;
|
||||
this.GCallbackWidgetFocuEvent_t = ctypes.FunctionType(
|
||||
ctypes.default_abi, gobject.gboolean,
|
||||
[this.GtkWidget.ptr, gdk.GdkEventFocus.ptr, gobject.gpointer]).ptr;
|
||||
|
||||
|
||||
lib.lazy_bind("gtk_icon_theme_get_default", this.GtkIconTheme.ptr);
|
||||
lib.lazy_bind("gtk_icon_theme_get_for_screen", this.GtkIconTheme.ptr, gdk.GdkScreen.ptr);
|
||||
@ -85,6 +89,7 @@ function gtk_defines(lib) {
|
||||
lib.lazy_bind("gtk_status_icon_set_from_icon_name", ctypes.void_t, this.GtkStatusIcon.ptr, gobject.gchar.ptr);
|
||||
lib.lazy_bind("gtk_status_icon_set_from_gicon", ctypes.void_t, this.GtkStatusIcon.ptr, gio.GIcon.ptr);
|
||||
lib.lazy_bind("gtk_status_icon_set_tooltip_text", ctypes.void_t, this.GtkStatusIcon.ptr, ctypes.char.ptr);
|
||||
lib.lazy_bind("gtk_status_icon_set_blinking", ctypes.void_t, this.GtkStatusIcon.ptr, gobject.gboolean); // deprecated in gtk3
|
||||
lib.lazy_bind("gtk_status_icon_set_visible", ctypes.void_t, this.GtkStatusIcon.ptr, gobject.gboolean);
|
||||
lib.lazy_bind("gtk_menu_new", this.GtkMenu.ptr);
|
||||
lib.lazy_bind("gtk_menu_item_set_label", ctypes.void_t, this.GtkMenuItem.ptr, gobject.gchar.ptr);
|
||||
@ -104,7 +109,8 @@ function gtk_defines(lib) {
|
||||
lib.lazy_bind("gtk_status_icon_set_from_pixbuf", ctypes.void_t, this.GtkStatusIcon.ptr, gdk.GdkPixbuf.ptr);
|
||||
lib.lazy_bind("gtk_window_list_toplevels", gobject.GList.ptr);
|
||||
lib.lazy_bind("gtk_window_get_title", gobject.gchar.ptr, this.GtkWindow.ptr);
|
||||
|
||||
lib.lazy_bind("gtk_window_is_active", gobject.gboolean, this.GtkWindow.ptr);
|
||||
lib.lazy_bind("gtk_window_has_toplevel_focus", gobject.gboolean, this.GtkWindow.ptr);
|
||||
lib.lazy_bind("gtk_widget_get_has_window", gobject.gboolean, this.GtkWidget.ptr);
|
||||
lib.lazy_bind("gtk_widget_get_window", gdk.GdkWindow.ptr, this.GtkWidget.ptr);
|
||||
lib.lazy_bind("gtk_widget_get_parent_window", gdk.GdkWindow.ptr, this.GtkWidget.ptr);
|
||||
|
@ -11,7 +11,9 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
|
||||
Cu.import("resource://firetray/ctypes/linux/gio.jsm");
|
||||
Cu.import("resource://firetray/ctypes/linux/gdk.jsm");
|
||||
Cu.import("resource://firetray/ctypes/linux/gtk.jsm");
|
||||
Cu.import("resource://firetray/linux/FiretrayWindow.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
firetray.Handler.subscribeLibsForClosing([gobject, gio, gtk]);
|
||||
|
||||
@ -32,6 +34,7 @@ firetray.IMStatusIcon = {
|
||||
o[FIRETRAY_IM_STATUS_OFFLINE] = null;
|
||||
return o;
|
||||
})(),
|
||||
callbacks: {onFocusIn: {}},
|
||||
|
||||
init: function() {
|
||||
if (!firetray.Handler.inMailApp) throw "IMStatusIcon for mail app only";
|
||||
@ -72,6 +75,31 @@ firetray.IMStatusIcon = {
|
||||
|
||||
setIconImage: function(name) {
|
||||
this.setIconImageFromGIcon(this.themedIcons[name]);
|
||||
},
|
||||
|
||||
setIconBlinking: function(blink) {
|
||||
gtk.gtk_status_icon_set_blinking(this.trayIcon, blink);
|
||||
},
|
||||
|
||||
/* we could also use x11.FocusIn... just wanted to try a different method */
|
||||
attachOnFocusInCallback: function(xid) {
|
||||
F.LOG("attachOnFocusInCallback xid="+xid);
|
||||
this.callbacks.onFocusIn[xid] = gtk.GCallbackWidgetFocuEvent_t(firetray.IMStatusIcon.onFocusIn);
|
||||
gobject.g_signal_connect(firetray.Handler.gtkWindows.get(xid),
|
||||
"focus-in-event", firetray.IMStatusIcon.callbacks.onFocusIn[xid], null);
|
||||
},
|
||||
|
||||
// NOTE: fluxbox issues a FocusIn event when switching workspace by hotkey :(
|
||||
// (http://sourceforge.net/tracker/index.php?func=detail&aid=3190205&group_id=35398&atid=413960)
|
||||
onFocusIn: function(widget, event, data) {
|
||||
F.LOG("onFocusIn");
|
||||
// let gdkEventFocus = ctypes.cast(event, gdk.GdkEventFocus.ptr);
|
||||
// let gdkWin = gdkEventFocus.contents.window;
|
||||
// let xid = firetray.Window.getXIDFromGdkWindow(gdkWin);
|
||||
// F.LOG("xid="+xid+" in="+gdkEventFocus.contents["in"]);
|
||||
firetray.InstantMessaging.stopIconBlinkingMaybe();
|
||||
}
|
||||
|
||||
// FIXME: TODO: onclick/activate -> chatHandler.showCurrentConversation()
|
||||
|
||||
}; // firetray.IMStatusIcon
|
||||
|
@ -516,7 +516,7 @@ firetray.Window = {
|
||||
if (firetray.Handler.windows[xwin].visible &&
|
||||
firetray.js.strEquals(xprop.contents.atom, x11.current.Atoms.WM_STATE) &&
|
||||
firetray.js.strEquals(xprop.contents.state, x11.PropertyNewValue)) {
|
||||
F.LOG("PropertyNotify: WM_STATE, send_event: "+xprop.contents.send_event+", state: "+xprop.contents.state);
|
||||
F.LOG("xid="+xwin+" PropertyNotify: WM_STATE, send_event: "+xprop.contents.send_event+", state: "+xprop.contents.state);
|
||||
winStates = firetray.Window.getXWindowStates(xwin);
|
||||
isHidden = winStates & FIRETRAY_XWINDOW_HIDDEN;
|
||||
}
|
||||
@ -536,7 +536,7 @@ firetray.Window = {
|
||||
if (hides_single_window) {
|
||||
firetray.Handler.hideWindow(xwin);
|
||||
} else
|
||||
firetray.Handler.hideAllWindows();
|
||||
firetray.Handler.hideAllWindows();
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,6 +595,12 @@ firetray.Handler.registerWindow = function(win) {
|
||||
this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(firetray.Window.filterWindow);
|
||||
gdk.gdk_window_add_filter(gdkWin, this.windows[xid].filterWindowCb, null);
|
||||
|
||||
// FIXME: isn't it (c)leaner to do it in x11 window filter ?
|
||||
if (firetray.Handler.isIMEnabled) {
|
||||
Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm");
|
||||
firetray.IMStatusIcon.attachOnFocusInCallback(xid);
|
||||
}
|
||||
|
||||
} catch (x) {
|
||||
firetray.Window.unregisterWindowByXID(xid);
|
||||
F.ERROR(x);
|
||||
@ -656,6 +662,20 @@ firetray.Handler.activateLastWindow = function(gtkStatusIcon, gdkEvent, userData
|
||||
return stopPropagation;
|
||||
};
|
||||
|
||||
firetray.Handler.findActiveWindow = function() {
|
||||
let activeWin = null;
|
||||
for (let xid in firetray.Handler.windows) {
|
||||
let gtkWin = firetray.Handler.gtkWindows.get(xid);
|
||||
let isActive = gtk.gtk_window_is_active(gtkWin);
|
||||
F.LOG(xid+" is active="+isActive);
|
||||
if (isActive) {
|
||||
activeWin = xid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return activeWin;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* init X11 Display and handled XAtoms.
|
||||
|
Loading…
Reference in New Issue
Block a user