diff --git a/README.md b/README.md index aabfc6b..c7ed96a 100644 --- a/README.md +++ b/README.md @@ -46,5 +46,5 @@ Acknowledgment * Some code borrowed from [Nils Mayer](https://addons.mozilla.org/fr/firefox/addon/minimizetotray-revived/ "MinToTrayR addon page"). -* kind support from Neil Deaking +* kind support from Neil Deaking, Bobby Holley diff --git a/src/chrome/content/options.xul b/src/chrome/content/options.xul index 629ffb2..1d9d47a 100644 --- a/src/chrome/content/options.xul +++ b/src/chrome/content/options.xul @@ -22,6 +22,7 @@ + @@ -38,7 +39,7 @@ - + + diff --git a/src/chrome/content/overlay.js b/src/chrome/content/overlay.js index 532b856..6380bd7 100644 --- a/src/chrome/content/overlay.js +++ b/src/chrome/content/overlay.js @@ -18,9 +18,8 @@ var firetrayChrome = { // Set up preference change observer firetray.Utils.prefService.QueryInterface(Ci.nsIPrefBranch2); firetray.Utils.prefService.addObserver("", firetrayChrome, false); - } - catch (ex) { - ERROR(ex); + } catch (x) { + ERROR(x); return false; } @@ -39,6 +38,14 @@ var firetrayChrome = { // NOTE: each new window gets a new firetrayChrome, and hence listens to // pref changes + if (!firetray.Handler.appStarted + && firetray.Utils.prefService.getBoolPref('start_hidden')) { + LOG('start_hidden'); + let winId = firetray.Handler.getWindowIdFromChromeWindow(win); + LOG('winId='+winId); + firetray.Handler.hideSingleWindow(winId); + } + LOG('Firetray LOADED: ' + init); return true; }, @@ -76,10 +83,12 @@ var firetrayChrome = { }, observe: function(subject, topic, data) { - // Observer for pref changes - if (topic != "nsPref:changed") return; - LOG('Pref changed: '+data); - // switch(data) { ... + switch (topic) { + case "nsPref:changed": + LOG('Pref changed: '+data); + break; + default: + } } }; diff --git a/src/chrome/locale/en-US/options.dtd b/src/chrome/locale/en-US/options.dtd index df2ec9e..bf960c2 100644 --- a/src/chrome/locale/en-US/options.dtd +++ b/src/chrome/locale/en-US/options.dtd @@ -8,7 +8,6 @@ - @@ -17,6 +16,8 @@ + + diff --git a/src/chrome/locale/en-US/overlay.properties b/src/chrome/locale/en-US/overlay.properties index 53b2e35..84b74e9 100644 --- a/src/chrome/locale/en-US/overlay.properties +++ b/src/chrome/locale/en-US/overlay.properties @@ -1,4 +1,5 @@ extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=A system tray extension for linux. popupMenu.itemLabel.Quit=Quit popupMenu.itemLabel.NewWindow=New window +popupMenu.itemLabel.NewMessage=New message tooltip.unread_messages=#1 unread message;#1 unread messages diff --git a/src/defaults/preferences/prefs.js b/src/defaults/preferences/prefs.js index a1db399..b20e81b 100644 --- a/src/defaults/preferences/prefs.js +++ b/src/defaults/preferences/prefs.js @@ -9,6 +9,7 @@ pref("browser.tabs.warnOnClose", false); pref("extensions.firetray.hides_on_close", true); pref("extensions.firetray.hides_on_minimize", true); pref("extensions.firetray.hides_single_window", false); +pref("extensions.firetray.start_hidden", false); pref("extensions.firetray.mail_notification", 1); pref("extensions.firetray.icon_text_color", "#000000"); diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index d954bf9..37472f3 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -34,7 +34,9 @@ firetray.Handler = { FILENAME_BLANK: null, FILENAME_NEWMAIL: null, runtimeOS: null, + mozAppId: null, inMailApp: false, + inBrowserApp: false, windows: {}, windowsCount: 0, visibleWindowsCount: 0, @@ -48,7 +50,6 @@ firetray.Handler = { this.FILENAME_NEWMAIL = firetray.Utils.chromeToPath( "chrome://firetray/skin/message-mail-new.png"); - // OS/platform checks this.runtimeABI = Services.appinfo.XPCOMABI; this.runtimeOS = Services.appinfo.OS; // "WINNT", "Linux", "Darwin" // version checked during install, so we shouldn't need to care @@ -66,14 +67,17 @@ firetray.Handler = { return false; } - // instanciate tray icon + this.mozAppId = Services.appinfo.ID; + if (this.mozAppId === THUNDERBIRD_ID || this.mozAppId === SEAMONKEY_ID) + this.inMailApp = true; + if (this.mozAppId === FIREFOX_ID || this.mozAppId === SEAMONKEY_ID) + this.inBrowserApp = true; + LOG('inMailApp: '+this.inMailApp+', inBrowserApp: '+this.inBrowserApp); + firetray.StatusIcon.init(); LOG('StatusIcon initialized'); - // check if in mail app - var mozAppId = Services.appinfo.ID; - if (mozAppId === THUNDERBIRD_ID || mozAppId === SEAMONKEY_ID) { - this.inMailApp = true; + if (this.inMailApp) { try { Cu.import("resource://firetray/FiretrayMessaging.jsm"); let prefMailNotification = firetray.Utils.prefService.getIntPref("mail_notification"); @@ -86,7 +90,8 @@ firetray.Handler = { return false; } } - LOG('inMailApp: '+this.inMailApp); + + Services.obs.addObserver(this, this.getAppStartupTopic(this.mozAppId), false); this.initialized = true; return true; @@ -105,9 +110,41 @@ firetray.Handler = { return false; } + Services.obs.removeObserver(this, this.getAppStartupTopic(this.mozAppId), false); + return true; }, + observe: function(subject, topic, data) { + switch (topic) { + case "sessionstore-windows-restored": + case "mail-startup-done": + case "final-ui-startup": + LOG("RECEIVED: "+topic+", launching timer"); + // sessionstore-windows-restored does not come after the realisation of + // all windows... so we wait a little + var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + timer.initWithCallback(function() { + firetray.Handler.appStarted = true; + LOG("*** appStarted ***"); + }, FIRETRAY_BROWSER_STARTUP_DELAY_MILLISECONDS, Ci.nsITimer.TYPE_ONE_SHOT); + break; + default: + } + }, + + getAppStartupTopic: function(id) { + switch (id) { + case FIREFOX_ID: + case SEAMONKEY_ID: + return 'sessionstore-windows-restored'; + case THUNDERBIRD_ID: + return 'mail-startup-done'; + default: + return 'final-ui-startup'; + } + }, + // these get overridden in OS-specific Window handlers setImage: function(filename) {}, setImageDefault: function() {}, @@ -154,13 +191,55 @@ firetray.Handler = { return winOut; }, + _getBrowserProperties: function() { + if (firetray.Handler.mozAppId === FIREFOX_ID) + return "chrome://branding/locale/browserconfig.properties"; + else if (firetray.Handler.mozAppId === SEAMONKEY_ID) + return "chrome://navigator-region/locale/region.properties"; + else return null; + }, + + _getHomePage: function() { + var prefDomain = "browser.startup.homepage"; + var url; + try { + url = Services.prefs.getComplexValue(prefDomain, + Components.interfaces.nsIPrefLocalizedString).data; + } catch (e) { + } + + // use this if we can't find the pref + if (!url) { + var SBS = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService); + var configBundle = SBS.createBundle(firetray.Handler._getBrowserProperties()); + url = configBundle.GetStringFromName(prefDomain); + } + + return url; + }, + openBrowserWindow: function() { - var handler = Components.classes["@mozilla.org/browser/clh;1"] - .getService(Components.interfaces.nsIBrowserHandler); - var homePage = handler.defaultArgs; - LOG("homePage="+homePage); - var win = Services.wm.getMostRecentWindow("navigator:browser"); // nsIDOMWindow=[object ChromeWindow] - win.open(homePage); + try { + var home = firetray.Handler._getHomePage(); + LOG("home="+home); + + // FIXME: obviously we need to wait to avoid seg fault on jsapi.cpp:827 + // 827 if (t->data.requestDepth) { + var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + timer.initWithCallback(function() { + for(var key in firetray.Handler.windows) break; + firetray.Handler.windows[key].chromeWin.open(home); + }, FIRETRAY_BROWSER_NEW_WINDOW_DELAY_MILLISECONDS, Ci.nsITimer.TYPE_ONE_SHOT); + } catch (x) { ERROR(x); } + }, + + openMailMessage: function() { + try { + var aURI = Services.io.newURI("mailto:", null, null); + var msgComposeService = Cc["@mozilla.org/messengercompose;1"] + .getService(Ci.nsIMsgComposeService); + msgComposeService.OpenComposeWindowWithURI (null, aURI); + } catch (x) { ERROR(x); } }, quitApplication: function() { diff --git a/src/modules/commons.js b/src/modules/commons.js index 934fb7b..e5d1906 100644 --- a/src/modules/commons.js +++ b/src/modules/commons.js @@ -6,7 +6,9 @@ var EXPORTED_SYMBOLS = [ "firetray", "LOG", "WARN", "ERROR", "FIREFOX_ID", "THUNDERBIRD_ID", "SEAMONKEY_ID", "getType", "isArray", "isEmpty", "strEquals", "FT_NOTIFICATION_DISABLED", "FT_NOTIFICATION_UNREAD_MESSAGE_COUNT", - "FT_NOTIFICATION_NEWMAIL_ICON", "FT_NOTIFICATION_CUSTOM_ICON" ]; + "FT_NOTIFICATION_NEWMAIL_ICON", "FT_NOTIFICATION_CUSTOM_ICON", + "FIRETRAY_BROWSER_STARTUP_DELAY_MILLISECONDS", + "FIRETRAY_BROWSER_NEW_WINDOW_DELAY_MILLISECONDS" ]; const Cc = Components.classes; const Ci = Components.interfaces; @@ -27,6 +29,9 @@ const FT_NOTIFICATION_UNREAD_MESSAGE_COUNT = 1; const FT_NOTIFICATION_NEWMAIL_ICON = 2; const FT_NOTIFICATION_CUSTOM_ICON = 3; +const FIRETRAY_BROWSER_STARTUP_DELAY_MILLISECONDS = 500; +const FIRETRAY_BROWSER_NEW_WINDOW_DELAY_MILLISECONDS = 50; + /** * firetray namespace. */ diff --git a/src/modules/gtk2/FiretrayStatusIcon.jsm b/src/modules/gtk2/FiretrayStatusIcon.jsm index 8a0ef3c..109a853 100644 --- a/src/modules/gtk2/FiretrayStatusIcon.jsm +++ b/src/modules/gtk2/FiretrayStatusIcon.jsm @@ -67,32 +67,40 @@ firetray.StatusIcon = { _buildPopupMenu: function() { this.menu = gtk.gtk_menu_new(); var menuShell = ctypes.cast(this.menu, gtk.GtkMenuShell.ptr); + var addMenuSeparator = false; - /* - * FIXME: somehow a ctypes callback calling win.open() seems to break - * main-thread-only rule :-( - * https://developer.mozilla.org/en/js-ctypes/js-ctypes_reference/Callbacks - * https://bugzilla.mozilla.org/show_bug.cgi?id=513778#c4 - * https://wiki.mozilla.org/Jsctypes/api#Callbacks - * consider using nsIJetpackService - */ -/* - var mozAppId = Services.appinfo.ID; - if (mozAppId === FIREFOX_ID || mozAppId === SEAMONKEY_ID) { // browser + if (firetray.Handler.inBrowserApp) { var menuItemNewWindowLabel = firetray.Utils.strings.GetStringFromName("popupMenu.itemLabel.NewWindow"); var menuItemNewWindow = gtk.gtk_image_menu_item_new_with_label( menuItemNewWindowLabel); gtk.gtk_menu_shell_append(menuShell, ctypes.cast(menuItemNewWindow, gtk.GtkWidget.ptr)); this.callbacks.menuItemNewWindowActivate = gobject.GCallback_t( - firetray.Handler.sendOpenBrowserWindowEvent); + firetray.Handler.openBrowserWindow); gobject.g_signal_connect(menuItemNewWindow, "activate", - firetray.StatusIcon.callbacks.menuItemNewWindowActivate, null); + firetray.StatusIcon.callbacks.menuItemNewWindowActivate, null); + addMenuSeparator = true; + } + + if (firetray.Handler.inMailApp) { + var menuItemNewMessageLabel = firetray.Utils.strings.GetStringFromName("popupMenu.itemLabel.NewMessage"); + var menuItemNewMessage = gtk.gtk_image_menu_item_new_with_label( + menuItemNewMessageLabel); + gtk.gtk_menu_shell_append(menuShell, ctypes.cast(menuItemNewMessage, gtk.GtkWidget.ptr)); + + this.callbacks.menuItemNewMessageActivate = gobject.GCallback_t( + firetray.Handler.openMailMessage); + gobject.g_signal_connect(menuItemNewMessage, "activate", + firetray.StatusIcon.callbacks.menuItemNewMessageActivate, null); + + addMenuSeparator = true; + } + + if (addMenuSeparator) { var menuSeparator = gtk.gtk_separator_menu_item_new(); gtk.gtk_menu_shell_append(menuShell, ctypes.cast(menuSeparator, gtk.GtkWidget.ptr)); } -*/ // shouldn't need to convert to utf8 thank to js-ctypes var menuItemQuitLabel = firetray.Utils.strings.GetStringFromName("popupMenu.itemLabel.Quit"); diff --git a/src/modules/gtk2/FiretrayWindow.jsm b/src/modules/gtk2/FiretrayWindow.jsm index 7628114..b7c1004 100644 --- a/src/modules/gtk2/FiretrayWindow.jsm +++ b/src/modules/gtk2/FiretrayWindow.jsm @@ -328,6 +328,7 @@ firetray.Window = { let [propsFound, nitems] = firetray.Window.getXWindowProperties(xwin, x11.current.Atoms._NET_WM_DESKTOP); LOG("DESKTOP propsFound, nitems="+propsFound+", "+nitems); + if (!propsFound) return null; if (strEquals(nitems.value, 0)) WARN("desktop number not found");