mirror of
https://github.com/moparisthebest/FireTray
synced 2024-08-13 15:53:47 -04:00
* extract FiretrayPopupMenu.jsm from FiretrayStatusIcon.jsm
* fix visibilityRate * fix: have only one prefListener * refactor PopupMenu functions * clean
This commit is contained in:
parent
fc51dca3fe
commit
eb8ce310f4
@ -8,20 +8,10 @@ if ("undefined" == typeof(Ci)) var Ci = Components.interfaces;
|
||||
if ("undefined" == typeof(Cu)) var Cu = Components.utils;
|
||||
|
||||
// https://groups.google.com/group/mozilla.dev.extensions/browse_thread/thread/e89e9c2a834ff2b6#
|
||||
var firetrayChrome = {
|
||||
var firetrayChrome = { // each new window gets a new firetrayChrome !
|
||||
|
||||
onLoad: function(win) {
|
||||
// strings a chrome-specific
|
||||
this.strings = document.getElementById("firetray-strings");
|
||||
|
||||
try {
|
||||
// Set up preference change observer
|
||||
firetray.Utils.prefService.QueryInterface(Ci.nsIPrefBranch2);
|
||||
firetray.Utils.prefService.addObserver("", firetrayChrome, false);
|
||||
} catch (x) {
|
||||
ERROR(x);
|
||||
return false;
|
||||
}
|
||||
this.strings = document.getElementById("firetray-strings"); // chrome-specific
|
||||
|
||||
LOG("Handler initialized: "+firetray.Handler.initialized);
|
||||
let init = firetray.Handler.initialized || firetray.Handler.init();
|
||||
@ -35,8 +25,6 @@ var firetrayChrome = {
|
||||
|
||||
// prevent window closing.
|
||||
win.addEventListener('close', firetrayChrome.onClose, true);
|
||||
// NOTE: each new window gets a new firetrayChrome, and hence listens to
|
||||
// pref changes
|
||||
|
||||
if (!firetray.Handler.appStarted
|
||||
&& firetray.Utils.prefService.getBoolPref('start_hidden')) {
|
||||
@ -51,13 +39,10 @@ var firetrayChrome = {
|
||||
},
|
||||
|
||||
onQuit: function(win) {
|
||||
// Remove observer
|
||||
firetray.Utils.prefService.removeObserver("", firetrayChrome);
|
||||
|
||||
firetray.Handler.unregisterWindow(win);
|
||||
|
||||
/* NOTE: don't firetray.Handler.initialized=false here, otherwise after a
|
||||
window close, a new window will create a new handler (and hence, a new
|
||||
/* NOTE: don't do firetray.Handler.initialized=false here, otherwise after
|
||||
a window close, a new window will create a new handler (and hence, a new
|
||||
tray icon) */
|
||||
LOG('Firetray UNLOADED !');
|
||||
},
|
||||
@ -80,28 +65,7 @@ var firetrayChrome = {
|
||||
firetray.Handler.hideAllWindows();
|
||||
event && event.preventDefault(); // no event when called directly (xul)
|
||||
}
|
||||
},
|
||||
|
||||
// the chosen design is not to destroy/re-create existing objects, but
|
||||
// show/hide (Gtk objects) and apply/not (callbacks) them instead
|
||||
observe: function(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "nsPref:changed":
|
||||
LOG('Pref changed: '+data);
|
||||
switch (data) {
|
||||
case 'hides_single_window':
|
||||
firetray.Handler.updatePopupMenu();
|
||||
break;
|
||||
case 'show_icon_on_hide':
|
||||
firetray.Handler.showHideIcon();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// should be sufficient for a delayed Startup (no need for window.setTimeout())
|
||||
|
@ -11,6 +11,7 @@ Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://firetray/ctypes/gobject.jsm");
|
||||
Cu.import("resource://firetray/ctypes/gtk.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
Cu.import("resource://firetray/FiretrayPrefListener.jsm");
|
||||
Cu.import("resource://firetray/FiretrayVersionChange.jsm");
|
||||
|
||||
/**
|
||||
@ -45,6 +46,8 @@ firetray.Handler = {
|
||||
visibleWindowsCount: 0,
|
||||
|
||||
init: function() { // does creates icon
|
||||
firetray.PrefListener.register(false);
|
||||
|
||||
this.appNameOriginal = Services.appinfo.name;
|
||||
this.FILENAME_DEFAULT = firetray.Utils.chromeToPath(
|
||||
"chrome://firetray/skin/" + this.appNameOriginal.toLowerCase() + this.FILENAME_SUFFIX);
|
||||
@ -105,6 +108,8 @@ firetray.Handler = {
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
firetray.PrefListener.unregister();
|
||||
|
||||
if (this.inMailApp)
|
||||
firetray.Messaging.shutdown();
|
||||
firetray.StatusIcon.shutdown();
|
||||
@ -272,3 +277,19 @@ firetray.Handler = {
|
||||
}
|
||||
|
||||
}; // firetray.Handler
|
||||
|
||||
|
||||
firetray.PrefListener = new PrefListener(
|
||||
"extensions.firetray.",
|
||||
function(branch, name) {
|
||||
LOG('Pref changed: '+name);
|
||||
switch (name) {
|
||||
case 'hides_single_window':
|
||||
firetray.Handler.updatePopupMenu();
|
||||
break;
|
||||
case 'show_icon_on_hide':
|
||||
firetray.Handler.showHideIcon();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
50
src/modules/FiretrayPrefListener.jsm
Normal file
50
src/modules/FiretrayPrefListener.jsm
Normal file
@ -0,0 +1,50 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// https://developer.mozilla.org/en/Code_snippets/Preferences
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "PrefListener" ];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {string} branch_name
|
||||
* @param {Function} callback must have the following arguments:
|
||||
* branch, pref_leaf_name
|
||||
*/
|
||||
function PrefListener(branch_name, callback) {
|
||||
// Keeping a reference to the observed preference branch or it will get
|
||||
// garbage collected.
|
||||
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService);
|
||||
this._branch = prefService.getBranch(branch_name);
|
||||
this._branch.QueryInterface(Components.interfaces.nsIPrefBranch2);
|
||||
this._callback = callback;
|
||||
}
|
||||
|
||||
PrefListener.prototype.observe = function(subject, topic, data) {
|
||||
if (topic == 'nsPref:changed')
|
||||
this._callback(this._branch, data);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean=} trigger if true triggers the registered function
|
||||
* on registration, that is, when this method is called.
|
||||
*/
|
||||
PrefListener.prototype.register = function(trigger) {
|
||||
this._branch.addObserver('', this, false);
|
||||
if (trigger) {
|
||||
let that = this;
|
||||
this._branch.getChildList('', {}).
|
||||
forEach(function (pref_leaf_name)
|
||||
{ that._callback(that._branch, pref_leaf_name); });
|
||||
}
|
||||
};
|
||||
|
||||
PrefListener.prototype.unregister = function() {
|
||||
if (this._branch)
|
||||
this._branch.removeObserver('', this);
|
||||
};
|
221
src/modules/gtk2/FiretrayPopupMenu.jsm
Normal file
221
src/modules/gtk2/FiretrayPopupMenu.jsm
Normal file
@ -0,0 +1,221 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "firetray" ];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://firetray/ctypes/gobject.jsm");
|
||||
Cu.import("resource://firetray/ctypes/gtk.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
|
||||
if ("undefined" == typeof(firetray.StatusIcon))
|
||||
ERROR("This module MUST be imported from/after StatusIcon !");
|
||||
|
||||
|
||||
firetray.PopupMenu = {
|
||||
initialized: false,
|
||||
// pointers to JS functions. MUST LIVE DURING ALL THE EXECUTION
|
||||
callbacks: {menuItemWindowActivate: {}},
|
||||
menu: null,
|
||||
menuSeparatorWindows: null,
|
||||
MIN_FONT_SIZE: 4,
|
||||
|
||||
init: function() { // FIXME: function too long
|
||||
this.menu = gtk.gtk_menu_new();
|
||||
var menuShell = ctypes.cast(this.menu, gtk.GtkMenuShell.ptr);
|
||||
var addMenuSeparator = false;
|
||||
|
||||
if (firetray.Handler.inBrowserApp) {
|
||||
var menuItemNewWindowLabel = firetray.Utils.strings.GetStringFromName("popupMenu.itemLabel.NewWindow");
|
||||
var menuItemNewWindow = gtk.gtk_image_menu_item_new_with_label(
|
||||
menuItemNewWindowLabel);
|
||||
var menuItemNewWindowIcon = gtk.gtk_image_new_from_stock(
|
||||
"gtk-new", gtk.GTK_ICON_SIZE_MENU);
|
||||
gtk.gtk_image_menu_item_set_image(menuItemNewWindow, menuItemNewWindowIcon);
|
||||
gtk.gtk_menu_shell_append(menuShell, ctypes.cast(menuItemNewWindow, gtk.GtkWidget.ptr));
|
||||
|
||||
this.callbacks.menuItemNewWindowActivate = gobject.GCallback_t(
|
||||
firetray.Handler.openBrowserWindow);
|
||||
gobject.g_signal_connect(menuItemNewWindow, "activate",
|
||||
firetray.PopupMenu.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);
|
||||
var menuItemNewMessageIcon = gtk.gtk_image_new_from_stock(
|
||||
"gtk-edit", gtk.GTK_ICON_SIZE_MENU);
|
||||
gtk.gtk_image_menu_item_set_image(menuItemNewMessage, menuItemNewMessageIcon);
|
||||
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.PopupMenu.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");
|
||||
var menuItemQuit = gtk.gtk_image_menu_item_new_with_label(
|
||||
menuItemQuitLabel);
|
||||
var menuItemQuitIcon = gtk.gtk_image_new_from_stock(
|
||||
"gtk-quit", gtk.GTK_ICON_SIZE_MENU);
|
||||
gtk.gtk_image_menu_item_set_image(menuItemQuit, menuItemQuitIcon);
|
||||
gtk.gtk_menu_shell_append(menuShell, ctypes.cast(menuItemQuit, gtk.GtkWidget.ptr));
|
||||
|
||||
this.callbacks.menuItemQuitActivate = gobject.GCallback_t(
|
||||
firetray.Handler.quitApplication);
|
||||
gobject.g_signal_connect(menuItemQuit, "activate",
|
||||
firetray.PopupMenu.callbacks.menuItemQuitActivate, null);
|
||||
|
||||
var menuWidget = ctypes.cast(this.menu, gtk.GtkWidget.ptr);
|
||||
gtk.gtk_widget_show_all(menuWidget);
|
||||
|
||||
var menuSeparatorWindows = gtk.gtk_separator_menu_item_new();
|
||||
gtk.gtk_menu_shell_prepend(menuShell, ctypes.cast(menuSeparatorWindows, gtk.GtkWidget.ptr));
|
||||
this.menuSeparatorWindows = menuSeparatorWindows;
|
||||
|
||||
this.initialized = true;
|
||||
return true;
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
firetray.Utils.tryCloseLibs([gobject, gtk]);
|
||||
this.initialized = false;
|
||||
},
|
||||
|
||||
popup: function(icon, button, activateTime, menu) {
|
||||
LOG("menu-popup");
|
||||
LOG("ARGS="+icon+", "+button+", "+activateTime+", "+menu);
|
||||
|
||||
try {
|
||||
var gtkMenuPtr = ctypes.cast(menu, gtk.GtkMenu.ptr);
|
||||
var iconGpointer = ctypes.cast(icon, gobject.gpointer);
|
||||
gtk.gtk_menu_popup(
|
||||
gtkMenuPtr, null, null, gtk.gtk_status_icon_position_menu,
|
||||
iconGpointer, button, activateTime);
|
||||
} catch (x) { ERROR(x); }
|
||||
},
|
||||
|
||||
// we'll be creating menuItems for windows (and not showing them) even if
|
||||
// hides_single_window is false, because if hides_single_window becomes true,
|
||||
// we'll just have to show the menuItems
|
||||
addWindowItem: function(xid) { // on registerWindow
|
||||
var menuItemWindow = this.addItem();
|
||||
firetray.Handler.gtkPopupMenuWindowItems.insert(xid, menuItemWindow);
|
||||
|
||||
this.callbacks.menuItemWindowActivate[xid] = gobject.GCallback_t(
|
||||
function(){firetray.Handler.showSingleWindow(xid);});
|
||||
gobject.g_signal_connect(menuItemWindow, "activate",
|
||||
firetray.PopupMenu.callbacks.menuItemWindowActivate[xid], null);
|
||||
this.setWindowItemLabel(menuItemWindow, xid); // default to xid
|
||||
|
||||
LOG("add gtkPopupMenuWindowItems: "+firetray.Handler.gtkPopupMenuWindowItems.count);
|
||||
},
|
||||
|
||||
addItem: function() {
|
||||
var menuItem = gtk.gtk_image_menu_item_new();
|
||||
var menuShell = ctypes.cast(this.menu, gtk.GtkMenuShell.ptr);
|
||||
gtk.gtk_menu_shell_prepend(menuShell, ctypes.cast(menuItem, gtk.GtkWidget.ptr));
|
||||
return menuItem;
|
||||
},
|
||||
|
||||
removeWindowItem: function(xid) { // on unregisterWindow
|
||||
let menuItemWindow = firetray.Handler.gtkPopupMenuWindowItems.get(xid);
|
||||
firetray.Handler.gtkPopupMenuWindowItems.remove(xid);
|
||||
this.removeItem(menuItemWindow);
|
||||
LOG("remove gtkPopupMenuWindowItems: "+firetray.Handler.gtkPopupMenuWindowItems.count);
|
||||
},
|
||||
removeItem: function(item) {
|
||||
gtk.gtk_widget_destroy(ctypes.cast(item, gtk.GtkWidget.ptr));
|
||||
},
|
||||
|
||||
showAllWindowItemsOnlyVisibleWindows: function() {
|
||||
for (let xid in firetray.Handler.windows)
|
||||
if (!firetray.Handler.windows[xid].visibility)
|
||||
this.showSingleWindowItem(xid);
|
||||
},
|
||||
|
||||
showSingleWindowItem: function(xid) {
|
||||
LOG("showSingleWindowItem");
|
||||
let menuItemWindow = firetray.Handler.gtkPopupMenuWindowItems.get(xid);
|
||||
this.showItem(menuItemWindow);
|
||||
this.setWindowItemLabel(menuItemWindow, firetray.Window.getWindowTitle(xid));
|
||||
this.showWindowSeparator();
|
||||
},
|
||||
|
||||
showItem: function(menuItem) {
|
||||
gtk.gtk_widget_show(ctypes.cast(menuItem, gtk.GtkWidget.ptr));
|
||||
},
|
||||
|
||||
setWindowItemLabel: function(menuItem, label) {
|
||||
LOG("about to set title: "+label);
|
||||
if (label)
|
||||
gtk.gtk_menu_item_set_label(ctypes.cast(menuItem, gtk.GtkMenuItem.ptr), label);
|
||||
},
|
||||
|
||||
hideAllWindowItems: function() {
|
||||
for (let xid in firetray.Handler.windows)
|
||||
this.hideSingleWindowItemAndSeparator(xid);
|
||||
},
|
||||
|
||||
// PopupMenu.hideItem(firetray.Handler.gtkPopupMenuWindowItems.get(xid))
|
||||
hideSingleWindowItemAndSeparator: function(xid) {
|
||||
this.hideSingleWindowItem(xid);
|
||||
this.hideWindowSeparator();
|
||||
},
|
||||
|
||||
hideSingleWindowItemAndSeparatorMaybe: function(xid) {
|
||||
this.hideSingleWindowItem(xid);
|
||||
if (firetray.Handler.visibleWindowsCount === firetray.Handler.windowsCount)
|
||||
this.hideWindowSeparator();
|
||||
},
|
||||
|
||||
hideSingleWindowItem: function(xid) {
|
||||
LOG("hideSingleWindowItem");
|
||||
let menuItemWindow = firetray.Handler.gtkPopupMenuWindowItems.get(xid);
|
||||
this.hideItem(menuItemWindow);
|
||||
},
|
||||
|
||||
hideItem: function(menuItem) {
|
||||
gtk.gtk_widget_hide(ctypes.cast(menuItem, gtk.GtkWidget.ptr));
|
||||
},
|
||||
|
||||
showWindowSeparator: function() {
|
||||
LOG("showing menuSeparatorWindows");
|
||||
gtk.gtk_widget_show(ctypes.cast(this.menuSeparatorWindows, gtk.GtkWidget.ptr));
|
||||
},
|
||||
hideWindowSeparator: function() {
|
||||
LOG("hiding menuSeparatorWindows");
|
||||
gtk.gtk_widget_hide(ctypes.cast(this.menuSeparatorWindows, gtk.GtkWidget.ptr));
|
||||
}
|
||||
|
||||
}; // firetray.PopupMenu
|
||||
|
||||
|
||||
firetray.Handler.popupMenuWindowItemsHandled = function() {
|
||||
return (firetray.Handler.inBrowserApp &&
|
||||
firetray.Utils.prefService.getBoolPref('hides_single_window'));
|
||||
};
|
||||
|
||||
firetray.Handler.updatePopupMenu = function() {
|
||||
if (firetray.Handler.popupMenuWindowItemsHandled())
|
||||
firetray.PopupMenu.showAllWindowItemsOnlyVisibleWindows();
|
||||
else
|
||||
firetray.PopupMenu.hideAllWindowItems();
|
||||
};
|
@ -13,10 +13,8 @@ Cu.import("resource://firetray/ctypes/cairo.jsm");
|
||||
Cu.import("resource://firetray/ctypes/gobject.jsm");
|
||||
Cu.import("resource://firetray/ctypes/gdk.jsm");
|
||||
Cu.import("resource://firetray/ctypes/gtk.jsm");
|
||||
Cu.import("resource://firetray/ctypes/libc.jsm");
|
||||
Cu.import("resource://firetray/ctypes/pango.jsm");
|
||||
Cu.import("resource://firetray/ctypes/pangocairo.jsm");
|
||||
Cu.import("resource://firetray/ctypes/x11.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
|
||||
if ("undefined" == typeof(firetray.Handler))
|
||||
@ -26,11 +24,8 @@ if ("undefined" == typeof(firetray.Handler))
|
||||
firetray.StatusIcon = {
|
||||
initialized: false,
|
||||
// pointers to JS functions. MUST LIVE DURING ALL THE EXECUTION
|
||||
callbacks: {menuItemWindowActivate: {}},
|
||||
callbacks: {},
|
||||
trayIcon: null,
|
||||
menu: null,
|
||||
menuSeparatorWindows: null,
|
||||
MIN_FONT_SIZE: 4,
|
||||
|
||||
init: function() {
|
||||
try {
|
||||
@ -43,16 +38,13 @@ firetray.StatusIcon = {
|
||||
|
||||
firetray.Handler.setIconImageDefault();
|
||||
|
||||
this._buildPopupMenu();
|
||||
|
||||
firetray.Handler.setIconTooltipDefault();
|
||||
|
||||
LOG("showHideAllWindows: "+firetray.Handler.hasOwnProperty("showHideAllWindows"));
|
||||
this.callbacks.iconActivate = gtk.GCallbackStatusIconActivate_t(
|
||||
firetray.Handler.showHideAllWindows);
|
||||
let handlerId = gobject.g_signal_connect(firetray.StatusIcon.trayIcon,
|
||||
"activate", firetray.StatusIcon.callbacks.iconActivate, null);
|
||||
LOG("g_connect activate="+handlerId);
|
||||
Cu.import("resource://firetray/gtk2/FiretrayPopupMenu.jsm");
|
||||
if (!firetray.PopupMenu.init())
|
||||
return false;
|
||||
|
||||
this.addCallbacks();
|
||||
|
||||
this.initialized = true;
|
||||
return true;
|
||||
@ -63,179 +55,23 @@ firetray.StatusIcon = {
|
||||
this.initialized = false;
|
||||
},
|
||||
|
||||
_buildPopupMenu: function() { // FIXME: function too long
|
||||
this.menu = gtk.gtk_menu_new();
|
||||
var menuShell = ctypes.cast(this.menu, gtk.GtkMenuShell.ptr);
|
||||
var addMenuSeparator = false;
|
||||
|
||||
if (firetray.Handler.inBrowserApp) {
|
||||
var menuItemNewWindowLabel = firetray.Utils.strings.GetStringFromName("popupMenu.itemLabel.NewWindow");
|
||||
var menuItemNewWindow = gtk.gtk_image_menu_item_new_with_label(
|
||||
menuItemNewWindowLabel);
|
||||
var menuItemNewWindowIcon = gtk.gtk_image_new_from_stock(
|
||||
"gtk-new", gtk.GTK_ICON_SIZE_MENU);
|
||||
gtk.gtk_image_menu_item_set_image(menuItemNewWindow, menuItemNewWindowIcon);
|
||||
gtk.gtk_menu_shell_append(menuShell, ctypes.cast(menuItemNewWindow, gtk.GtkWidget.ptr));
|
||||
|
||||
this.callbacks.menuItemNewWindowActivate = gobject.GCallback_t(
|
||||
firetray.Handler.openBrowserWindow);
|
||||
gobject.g_signal_connect(menuItemNewWindow, "activate",
|
||||
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);
|
||||
var menuItemNewMessageIcon = gtk.gtk_image_new_from_stock(
|
||||
"gtk-edit", gtk.GTK_ICON_SIZE_MENU);
|
||||
gtk.gtk_image_menu_item_set_image(menuItemNewMessage, menuItemNewMessageIcon);
|
||||
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");
|
||||
var menuItemQuit = gtk.gtk_image_menu_item_new_with_label(
|
||||
menuItemQuitLabel);
|
||||
var menuItemQuitIcon = gtk.gtk_image_new_from_stock(
|
||||
"gtk-quit", gtk.GTK_ICON_SIZE_MENU);
|
||||
gtk.gtk_image_menu_item_set_image(menuItemQuit, menuItemQuitIcon);
|
||||
gtk.gtk_menu_shell_append(menuShell, ctypes.cast(menuItemQuit, gtk.GtkWidget.ptr));
|
||||
|
||||
this.callbacks.menuItemQuitActivate = gobject.GCallback_t(
|
||||
firetray.Handler.quitApplication);
|
||||
gobject.g_signal_connect(menuItemQuit, "activate",
|
||||
firetray.StatusIcon.callbacks.menuItemQuitActivate, null);
|
||||
|
||||
var menuWidget = ctypes.cast(this.menu, gtk.GtkWidget.ptr);
|
||||
gtk.gtk_widget_show_all(menuWidget);
|
||||
|
||||
addCallbacks: function() {
|
||||
/* NOTE: here we do use a function handler (instead of a function
|
||||
definition) because we need the args passed to it ! As a consequence, we
|
||||
need to abandon 'this' in popupMenu() */
|
||||
let that = this;
|
||||
this.callbacks.popupMenu = gtk.GCallbackMenuPopup_t(that.popupMenu);
|
||||
definition) because we need the args passed to it ! As a consequence, we
|
||||
need to abandon 'this' in PopupMenu.popup() */
|
||||
this.callbacks.menuPopup = gtk.GCallbackMenuPopup_t(firetray.PopupMenu.popup);
|
||||
gobject.g_signal_connect(this.trayIcon, "popup-menu",
|
||||
firetray.StatusIcon.callbacks.popupMenu, this.menu);
|
||||
this.callbacks.onScroll = gtk.GCallbackOnScroll_t(that.onScroll);
|
||||
firetray.StatusIcon.callbacks.menuPopup, firetray.PopupMenu.menu);
|
||||
this.callbacks.onScroll = gtk.GCallbackOnScroll_t(firetray.StatusIcon.onScroll);
|
||||
gobject.g_signal_connect(this.trayIcon, "scroll-event",
|
||||
firetray.StatusIcon.callbacks.onScroll, null);
|
||||
firetray.StatusIcon.callbacks.onScroll, null);
|
||||
|
||||
var menuSeparatorWindows = gtk.gtk_separator_menu_item_new();
|
||||
gtk.gtk_menu_shell_prepend(menuShell, ctypes.cast(menuSeparatorWindows, gtk.GtkWidget.ptr));
|
||||
firetray.StatusIcon.menuSeparatorWindows = menuSeparatorWindows;
|
||||
|
||||
},
|
||||
|
||||
popupMenu: function(icon, button, activateTime, menu) {
|
||||
LOG("menu-popup");
|
||||
LOG("ARGS="+icon+", "+button+", "+activateTime+", "+menu);
|
||||
|
||||
try {
|
||||
var gtkMenuPtr = ctypes.cast(menu, gtk.GtkMenu.ptr);
|
||||
var iconGpointer = ctypes.cast(icon, gobject.gpointer);
|
||||
gtk.gtk_menu_popup(
|
||||
gtkMenuPtr, null, null, gtk.gtk_status_icon_position_menu,
|
||||
iconGpointer, button, activateTime);
|
||||
} catch (x) {
|
||||
ERROR(x);
|
||||
}
|
||||
},
|
||||
|
||||
// we keep the definition here, as it is(?) specific to the
|
||||
// platform-dependant StatusIcon (there might be no popup menu in other
|
||||
// platforms)
|
||||
popupMenuWindowItemsHandled: function() {
|
||||
return (firetray.Handler.inBrowserApp &&
|
||||
firetray.Utils.prefService.getBoolPref('hides_single_window'));
|
||||
},
|
||||
|
||||
// we'll be creating menuItems for windows (and not showing them) even if
|
||||
// hides_single_window is false, because if hides_single_window becomes true,
|
||||
// we'll just have to show the menuItems
|
||||
addPopupMenuWindowItem: function(xid) { // on registerWindow
|
||||
var menuItemWindow = gtk.gtk_image_menu_item_new();
|
||||
firetray.Handler.gtkPopupMenuWindowItems.insert(xid, menuItemWindow);
|
||||
|
||||
var menuShell = ctypes.cast(firetray.StatusIcon.menu, gtk.GtkMenuShell.ptr);
|
||||
gtk.gtk_menu_shell_prepend(menuShell,
|
||||
ctypes.cast(menuItemWindow, gtk.GtkWidget.ptr));
|
||||
|
||||
this.callbacks.menuItemWindowActivate[xid] = gobject.GCallback_t(
|
||||
function(){firetray.Handler.showSingleWindow(xid);});
|
||||
gobject.g_signal_connect(menuItemWindow, "activate",
|
||||
firetray.StatusIcon.callbacks.menuItemWindowActivate[xid], null);
|
||||
|
||||
LOG("add gtkPopupMenuWindowItems: "+firetray.Handler.gtkPopupMenuWindowItems.count);
|
||||
},
|
||||
|
||||
setPopupMenuWindowItemLabel: function(menuItem, xid) {
|
||||
let title = firetray.Handler.windows[xid].baseWin.title;
|
||||
let tailIndex = title.indexOf(" - Mozilla "+firetray.Handler.appNameOriginal);
|
||||
if (tailIndex !== -1)
|
||||
title = title.substring(0, tailIndex);
|
||||
gtk.gtk_menu_item_set_label(ctypes.cast(menuItem, gtk.GtkMenuItem.ptr), title);
|
||||
},
|
||||
|
||||
removePopupMenuWindowItem: function(xid) { // on unregisterWindow
|
||||
let menuItemWindow = firetray.Handler.gtkPopupMenuWindowItems.get(xid);
|
||||
firetray.Handler.gtkPopupMenuWindowItems.remove(xid);
|
||||
gtk.gtk_widget_destroy(ctypes.cast(menuItemWindow, gtk.GtkWidget.ptr));
|
||||
|
||||
LOG("remove gtkPopupMenuWindowItems: "+firetray.Handler.gtkPopupMenuWindowItems.count);
|
||||
},
|
||||
|
||||
showAllPopupMenuWindowItems: function(filterVisibleWindows) {
|
||||
for (let xid in firetray.Handler.windows)
|
||||
if (!filterVisibleWindows || !firetray.Handler.windows[xid].visibility)
|
||||
this.showSinglePopupMenuWindowItem(xid);
|
||||
},
|
||||
|
||||
showSinglePopupMenuWindowItem: function(xid) {
|
||||
LOG("showSinglePopupMenuWindowItem");
|
||||
let menuItemWindow = firetray.Handler.gtkPopupMenuWindowItems.get(xid);
|
||||
gtk.gtk_widget_show(ctypes.cast(menuItemWindow, gtk.GtkWidget.ptr));
|
||||
this.setPopupMenuWindowItemLabel(menuItemWindow, xid); // not when creating item !
|
||||
this.showPopupMenuWindowSeparator();
|
||||
},
|
||||
|
||||
hideAllPopupMenuWindowItems: function(forceHideSeparator) {
|
||||
for (let xid in firetray.Handler.windows)
|
||||
this.hideSinglePopupMenuWindowItem(xid, forceHideSeparator);
|
||||
},
|
||||
|
||||
// PopupMenu.hideItem(firetray.Handler.gtkPopupMenuWindowItems.get(xid))
|
||||
hideSinglePopupMenuWindowItem: function(xid, forceHideSeparator) {
|
||||
LOG("hideSinglePopupMenuWindowItem");
|
||||
let menuItemWindow = firetray.Handler.gtkPopupMenuWindowItems.get(xid);
|
||||
gtk.gtk_widget_hide(ctypes.cast(menuItemWindow, gtk.GtkWidget.ptr)); // on hideSingleWindow
|
||||
|
||||
if (forceHideSeparator || (firetray.Handler.visibleWindowsCount === firetray.Handler.windowsCount)) {
|
||||
this.hidePopupMenuWindowSeparator();
|
||||
}
|
||||
},
|
||||
|
||||
showPopupMenuWindowSeparator: function() {
|
||||
LOG("showing menuSeparatorWindows");
|
||||
gtk.gtk_widget_show(ctypes.cast(firetray.StatusIcon.menuSeparatorWindows, gtk.GtkWidget.ptr));
|
||||
},
|
||||
hidePopupMenuWindowSeparator: function() {
|
||||
LOG("hiding menuSeparatorWindows");
|
||||
gtk.gtk_widget_hide(ctypes.cast(firetray.StatusIcon.menuSeparatorWindows, gtk.GtkWidget.ptr));
|
||||
LOG("showHideAllWindows: "+firetray.Handler.hasOwnProperty("showHideAllWindows"));
|
||||
this.callbacks.iconActivate = gtk.GCallbackStatusIconActivate_t(
|
||||
firetray.Handler.showHideAllWindows);
|
||||
let handlerId = gobject.g_signal_connect(firetray.StatusIcon.trayIcon,
|
||||
"activate", firetray.StatusIcon.callbacks.iconActivate, null);
|
||||
LOG("g_connect activate="+handlerId);
|
||||
},
|
||||
|
||||
onScroll: function(icon, event, data) {
|
||||
@ -421,10 +257,3 @@ firetray.Handler.setIconVisibility = function(visible) {
|
||||
gtk.gtk_status_icon_set_visible(firetray.StatusIcon.trayIcon, visible);
|
||||
return true;
|
||||
};
|
||||
|
||||
firetray.Handler.updatePopupMenu = function() {
|
||||
if (firetray.StatusIcon.popupMenuWindowItemsHandled())
|
||||
firetray.StatusIcon.showAllPopupMenuWindowItems(true);
|
||||
else
|
||||
firetray.StatusIcon.hideAllPopupMenuWindowItems(true);
|
||||
};
|
||||
|
@ -46,6 +46,13 @@ var _find_data_t = ctypes.StructType("_find_data_t", [
|
||||
{ outWindow: gtk.GtkWindow.ptr }
|
||||
]);
|
||||
|
||||
// NOTE: storing ctypes pointers into a JS object doesn't work: pointers are
|
||||
// "evolving" after a while (maybe due to back and forth conversion). So we
|
||||
// need to store them into a real ctypes array !
|
||||
firetray.Handler.gtkWindows = new ctypesMap(gtk.GtkWindow.ptr),
|
||||
firetray.Handler.gdkWindows = new ctypesMap(gdk.GdkWindow.ptr),
|
||||
firetray.Handler.gtkPopupMenuWindowItems = new ctypesMap(gtk.GtkImageMenuItem.ptr),
|
||||
|
||||
|
||||
firetray.Window = {
|
||||
|
||||
@ -172,7 +179,7 @@ firetray.Window = {
|
||||
throw new DeleteError();
|
||||
firetray.Handler.gtkWindows.remove(xid);
|
||||
firetray.Handler.gdkWindows.remove(xid);
|
||||
firetray.StatusIcon.removePopupMenuWindowItem(xid);
|
||||
firetray.PopupMenu.removeWindowItem(xid);
|
||||
} else {
|
||||
ERROR("can't unregister unknown window "+xid);
|
||||
return false;
|
||||
@ -368,6 +375,15 @@ firetray.Window = {
|
||||
return desktop;
|
||||
},
|
||||
|
||||
getWindowTitle: function(xid) {
|
||||
let title = firetray.Handler.windows[xid].baseWin.title;
|
||||
let tailIndex = title.indexOf(" - Mozilla "+firetray.Handler.appNameOriginal);
|
||||
if (tailIndex !== -1)
|
||||
return title.substring(0, tailIndex)
|
||||
else
|
||||
return null;
|
||||
},
|
||||
|
||||
filterWindow: function(xev, gdkEv, data) {
|
||||
if (!xev)
|
||||
return gdk.GDK_FILTER_CONTINUE;
|
||||
@ -395,19 +411,6 @@ firetray.Window = {
|
||||
}
|
||||
break;
|
||||
|
||||
case x11.ClientMessage: // not very useful
|
||||
LOG("ClientMessage");
|
||||
/* KEPT FOR LATER USE
|
||||
let xclient = ctypes.cast(xev, x11.XClientMessageEvent.ptr);
|
||||
LOG("xclient.data="+xclient.contents.data);
|
||||
LOG("message_type="+xclient.contents.message_type+", format="+xclient.contents.format);
|
||||
if (strEquals(xclient.contents.data[0], x11.current.Atoms.WM_DELETE_WINDOW)) {
|
||||
LOG("Delete Window prevented");
|
||||
return gdk.GDK_FILTER_REMOVE;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
|
||||
default:
|
||||
// LOG("xany.type="+xany.contents.type);
|
||||
break;
|
||||
@ -424,13 +427,6 @@ firetray.Window = {
|
||||
|
||||
///////////////////////// firetray.Handler overriding /////////////////////////
|
||||
|
||||
// NOTE: storing ctypes pointers into a JS object doesn't work: pointers are
|
||||
// "evolving" after a while (maybe due to back and forth conversion). So we
|
||||
// need to store them into a real ctypes array !
|
||||
firetray.Handler.gtkWindows = new ctypesMap(gtk.GtkWindow.ptr),
|
||||
firetray.Handler.gdkWindows = new ctypesMap(gdk.GdkWindow.ptr),
|
||||
firetray.Handler.gtkPopupMenuWindowItems = new ctypesMap(gtk.GtkImageMenuItem.ptr),
|
||||
|
||||
/** debug facility */
|
||||
firetray.Handler.dumpWindows = function() {
|
||||
LOG(firetray.Handler.windowsCount);
|
||||
@ -450,7 +446,7 @@ firetray.Handler.registerWindow = function(win) {
|
||||
try {
|
||||
this.gtkWindows.insert(xid, gtkWin);
|
||||
this.gdkWindows.insert(xid, gdkWin);
|
||||
firetray.StatusIcon.addPopupMenuWindowItem(xid);
|
||||
firetray.PopupMenu.addWindowItem(xid);
|
||||
} catch (x) {
|
||||
if (x.name === "RangeError") // instanceof not working :-(
|
||||
win.alert(x+"\n\nYou seem to have more than "+FIRETRAY_WINDOW_COUNT_MAX
|
||||
@ -470,12 +466,6 @@ firetray.Handler.registerWindow = function(win) {
|
||||
// delete_event_cb (in gtk2/nsWindow.cpp), but we prefer to use the
|
||||
// provided 'close' JS event
|
||||
|
||||
/* KEPT FOR LATER USE
|
||||
this.windows[xid].onWindowStateCb = gtk.GCallbackWindowStateEvent_t(firetray.Window.onWindowState);
|
||||
this.windows[xid].onWindowStateCbId = gobject.g_signal_connect(gtkWin, "window-state-event", this.windows[xid].onWindowStateCb, null);
|
||||
LOG("g_connect window-state-event="+this.windows[xid].onWindowStateCbId);
|
||||
*/
|
||||
|
||||
this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(firetray.Window.filterWindow);
|
||||
gdk.gdk_window_add_filter(gdkWin, this.windows[xid].filterWindowCb, null);
|
||||
|
||||
@ -492,7 +482,6 @@ firetray.Handler.registerWindow = function(win) {
|
||||
|
||||
firetray.Handler.unregisterWindow = function(win) {
|
||||
LOG("unregister window");
|
||||
|
||||
let xid = firetray.Window.getXIDFromChromeWindow(win);
|
||||
return firetray.Window.unregisterWindowByXID(xid);
|
||||
};
|
||||
@ -510,8 +499,8 @@ firetray.Handler.showSingleWindow = function(xid) {
|
||||
firetray.Handler.windows[xid].visibility = true;
|
||||
firetray.Handler.visibleWindowsCount += 1;
|
||||
|
||||
if (firetray.StatusIcon.popupMenuWindowItemsHandled())
|
||||
firetray.StatusIcon.hideSinglePopupMenuWindowItem(xid);
|
||||
if (firetray.Handler.popupMenuWindowItemsHandled())
|
||||
firetray.PopupMenu.hideSingleWindowItemAndSeparatorMaybe(xid);
|
||||
firetray.Handler.showHideIcon();
|
||||
};
|
||||
|
||||
@ -529,8 +518,8 @@ firetray.Handler.hideSingleWindow = function(xid) {
|
||||
firetray.Handler.windows[xid].visibility = false;
|
||||
firetray.Handler.visibleWindowsCount -= 1;
|
||||
|
||||
if (firetray.StatusIcon.popupMenuWindowItemsHandled())
|
||||
firetray.StatusIcon.showSinglePopupMenuWindowItem(xid);
|
||||
if (firetray.Handler.popupMenuWindowItemsHandled())
|
||||
firetray.PopupMenu.showSingleWindowItem(xid);
|
||||
firetray.Handler.showHideIcon();
|
||||
};
|
||||
|
||||
@ -543,10 +532,11 @@ firetray.Handler.showHideAllWindows = function(gtkStatusIcon, userData) {
|
||||
LOG("windowsCount="+firetray.Handler.windowsCount);
|
||||
let visibilityRate = firetray.Handler.visibleWindowsCount/firetray.Handler.windowsCount;
|
||||
LOG("visibilityRate="+visibilityRate);
|
||||
if (visibilityRate > 0.5) // TODO: should be configurable
|
||||
firetray.Handler.hideAllWindows();
|
||||
else
|
||||
if ((0.5 < visibilityRate) && (visibilityRate < 1)
|
||||
|| visibilityRate === 0) // TODO: should be configurable
|
||||
firetray.Handler.showAllWindows();
|
||||
else
|
||||
firetray.Handler.hideAllWindows();
|
||||
|
||||
let stopPropagation = true;
|
||||
return stopPropagation;
|
||||
|
Loading…
Reference in New Issue
Block a user