1
0
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:
foudfou 2012-01-23 04:04:05 +01:00
parent fc51dca3fe
commit eb8ce310f4
6 changed files with 341 additions and 266 deletions

View File

@ -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())

View File

@ -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:
}
});

View 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);
};

View 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();
};

View File

@ -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);
};

View File

@ -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;