[Pkg-mozext-commits] [firetray] 280/399: IM icon blinking when private message or cited in channel

David Prévot taffit at alioth.debian.org
Tue Oct 29 18:23:58 UTC 2013


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch dfsg-clean
in repository firetray.

commit 9f46ef6343816580428e1b2f6fdce840b2a368db
Author: foudfou <foudil.newbie+git at gmail.com>
Date:   Tue Aug 21 22:10:56 2012 +0200

    IM icon blinking when private message or cited in channel
---
 src/modules/FiretrayHandler.jsm            |    4 +-
 src/modules/FiretrayInstantMessaging.jsm   |   68 ++++++++++++++++++++++++++--
 src/modules/FiretrayMessaging.jsm          |    8 +++-
 src/modules/ctypes/linux/gdk.jsm           |    6 +++
 src/modules/ctypes/linux/gobject.jsm       |    1 +
 src/modules/ctypes/linux/gtk.jsm           |    8 +++-
 src/modules/linux/FiretrayIMStatusIcon.jsm |   28 ++++++++++++
 src/modules/linux/FiretrayWindow.jsm       |   24 +++++++++-
 8 files changed, 136 insertions(+), 11 deletions(-)

diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm
index 4cdee21..36ef9a1 100644
--- a/src/modules/FiretrayHandler.jsm
+++ b/src/modules/FiretrayHandler.jsm
@@ -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");
diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayInstantMessaging.jsm
index ee7304e..41730b7 100644
--- a/src/modules/FiretrayInstantMessaging.jsm
+++ b/src/modules/FiretrayInstantMessaging.jsm
@@ -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);
diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm
index f7d3de4..e6c05d3 100644
--- a/src/modules/FiretrayMessaging.jsm
+++ b/src/modules/FiretrayMessaging.jsm
@@ -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);
diff --git a/src/modules/ctypes/linux/gdk.jsm b/src/modules/ctypes/linux/gdk.jsm
index dda91fb..f437a86 100644
--- a/src/modules/ctypes/linux/gdk.jsm
+++ b/src/modules/ctypes/linux/gdk.jsm
@@ -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,
diff --git a/src/modules/ctypes/linux/gobject.jsm b/src/modules/ctypes/linux/gobject.jsm
index eb773be..ddd3be3 100644
--- a/src/modules/ctypes/linux/gobject.jsm
+++ b/src/modules/ctypes/linux/gobject.jsm
@@ -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;
diff --git a/src/modules/ctypes/linux/gtk.jsm b/src/modules/ctypes/linux/gtk.jsm
index 55c62a1..60f3670 100644
--- a/src/modules/ctypes/linux/gtk.jsm
+++ b/src/modules/ctypes/linux/gtk.jsm
@@ -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);
diff --git a/src/modules/linux/FiretrayIMStatusIcon.jsm b/src/modules/linux/FiretrayIMStatusIcon.jsm
index 4178215..008c7d3 100644
--- a/src/modules/linux/FiretrayIMStatusIcon.jsm
+++ b/src/modules/linux/FiretrayIMStatusIcon.jsm
@@ -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
diff --git a/src/modules/linux/FiretrayWindow.jsm b/src/modules/linux/FiretrayWindow.jsm
index 4cbd6a4..2c54ddc 100644
--- a/src/modules/linux/FiretrayWindow.jsm
+++ b/src/modules/linux/FiretrayWindow.jsm
@@ -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.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/firetray.git



More information about the Pkg-mozext-commits mailing list