Handle mouse events for auto hide feature by a frame script, for e10s

This commit is contained in:
YUKI Hiroshi 2014-11-11 17:45:12 +09:00
parent ee8918e460
commit 02bcfe5d8b
5 changed files with 313 additions and 31 deletions

View File

@ -0,0 +1,112 @@
(function(global) {
var DEBUG = false;
function mydump(aMessage) {
if (DEBUG)
dump('treestyletab(autohide) content utils: '+aMessage +'\n');
}
mydump('CONTENT SCRIPT LOADED <'+global.content.location+'>');
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
var { TreeStyleTabConstants } = Cu.import('resource://treestyletab-modules/constants.js', {});
function free() {
cleanup =
Cc = Ci = Cu = Cr =
TreeStyleTabConstants =
messageListener =
serializeMouseEvent =
handleEvent =
basicListening =
advanceListening =
mydump =
undefined;
}
var messageListener = function(aMessage) {
mydump('CONTENT MESSAGE LISTENED <'+global.content.location+'>');
mydump(JSON.stringify(aMessage.json));
switch (aMessage.json.command)
{
case TreeStyleTabConstants.COMMAND_SHUTDOWN:
global.removeMessageListener(TreeStyleTabConstants.MESSAGE_TYPE, messageListener);
if (basicListening) {
global.removeEventListener('mousedown', handleEvent, true);
global.removeEventListener('mouseup', handleEvent, true);
}
if (advanceListening) {
global.removeEventListener('mousemove', handleEvent, true);
}
free();
return;
case TreeStyleTabConstants.COMMAND_NOTIFY_AUTOHIDE_STATUS:
if (aMessage.json.params.basicListening && !basicListening) {
basicListening = true;
global.addEventListener('mousedown', handleEvent, true);
global.addEventListener('mouseup', handleEvent, true);
}
else if (!aMessage.json.params.basicListening && basicListening) {
basicListening = false;
global.removeEventListener('mousedown', handleEvent, true);
global.removeEventListener('mouseup', handleEvent, true);
}
if (aMessage.json.params.advanceListening && !advanceListening) {
advanceListening = true;
global.addEventListener('mousemove', handleEvent, true);
}
else if (!aMessage.json.params.advanceListening && advanceListening) {
advanceListening = false;
global.removeEventListener('mousemove', handleEvent, true);
}
return;
}
};
global.addMessageListener(TreeStyleTabConstants.MESSAGE_TYPE, messageListener);
function serializeMouseEvent(aEvent) {
return {
targetLocalName : aEvent.target.localName,
originalTargetLocalName : (aEvent.originalTarget || aEvent.target).localName,
altKey : aEvent.altKey,
ctrlKey : aEvent.ctrlKey,
metaKey : aEvent.metaKey,
shiftKey : aEvent.shiftKey,
screenX : aEvent.screenX,
screenY : aEvent.screenY,
clientX : aEvent.clientX,
clientY : aEvent.clientY
};
}
var basicListening = false;
var advanceListening = false;
function handleEvent(aEvent) {
switch (aEvent.type)
{
case 'mousedown':
global.sendAsyncMessage(TreeStyleTabConstants.MESSAGE_TYPE, {
command : TreeStyleTabConstants.COMMAND_REPORT_MOUSEDOWN,
event : serializeMouseEvent(aEvent)
});
break;
case 'mouseup':
global.sendAsyncMessage(TreeStyleTabConstants.MESSAGE_TYPE, {
command : TreeStyleTabConstants.COMMAND_REPORT_MOUSEUP,
event : serializeMouseEvent(aEvent)
});
break;
case 'mousemove':
global.sendAsyncMessage(TreeStyleTabConstants.MESSAGE_TYPE, {
command : TreeStyleTabConstants.COMMAND_REPORT_MOUSEMOVE,
event : serializeMouseEvent(aEvent)
});
break;
}
}
})(this);

View File

@ -44,6 +44,8 @@ const Cu = Components.utils;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
Cu.import('resource://treestyletab-modules/constants.js');
XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
@ -61,7 +63,7 @@ function AutoHideBrowser(aTabBrowser)
{
this.init(aTabBrowser);
}
AutoHideBrowser.prototype = {
AutoHideBrowser.prototype = inherit(TreeStyleTabConstants, {
kMODE : 'treestyletab-tabbar-autohide-mode',
kMODE_DISABLED : 0,
@ -235,10 +237,10 @@ AutoHideBrowser.prototype = {
sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_EXPANDED);
if (!(aReason & this.kSHOWHIDE_BY_API)) {
b.addEventListener('mousedown', this, true);
b.addEventListener('mouseup', this, true);
b.addEventListener('dragover', this, true);
b.addEventListener('dragleave', this, true);
sv.tabStripPlaceHolder.addEventListener('mousedown', this, true);
sv.tabStripPlaceHolder.addEventListener('mouseup', this, true);
sv.tabStrip.addEventListener('mousedown', this, true);
sv.tabStrip.addEventListener('mouseup', this, true);
if (this.shouldListenMouseMove)
@ -246,6 +248,7 @@ AutoHideBrowser.prototype = {
if (b == w.gBrowser && sv.shouldListenKeyEventsForAutoHide)
w.TreeStyleTabService.startListenKeyEventsFor(sv.LISTEN_FOR_AUTOHIDE);
this.userActionListening = true;
this.notifyStatusToAllTabs();
}
w.addEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
w.addEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
@ -271,16 +274,17 @@ AutoHideBrowser.prototype = {
this.screen.hidePopup();
if (this.userActionListening) {
b.removeEventListener('mousedown', this, true);
b.removeEventListener('mouseup', this, true);
b.removeEventListener('dragover', this, true);
b.removeEventListener('dragleave', this, true);
sv.tabStripPlaceHolder.removeEventListener('mousedown', this, true);
sv.tabStripPlaceHolder.removeEventListener('mouseup', this, true);
sv.tabStrip.removeEventListener('mousedown', this, true);
sv.tabStrip.removeEventListener('mouseup', this, true);
this.endListenMouseMove();
if (b == w.gBrowser)
w.TreeStyleTabService.endListenKeyEventsFor(sv.LISTEN_FOR_AUTOHIDE);
this.userActionListening = false;
this.notifyStatusToAllTabs();
}
w.removeEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
w.removeEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
@ -293,6 +297,19 @@ AutoHideBrowser.prototype = {
if (sv.isVertical)
sv.setTabStripAttribute('width', this.widthFromMode);
},
notifyStatusToAllTabs : function AHB_notifyStatusToAllTabs()
{
let tabs = this.treeStyleTab.getTabs(this.browser);
tabs.forEach(this.notifyStatusToTab, this);
},
notifyStatusToTab : function AHB_notifyStatusToTab(aTab)
{
aTab.__treestyletab__contentBridge.sendAsyncCommand(this.COMMAND_NOTIFY_AUTOHIDE_STATUS, {
basicListening : this.mouseMoveListening || this.userActionListening,
advanceListening : this.mouseMoveListening
});
},
// fullscreen
@ -325,22 +342,26 @@ AutoHideBrowser.prototype = {
{
if (this.mouseMoveListening) return;
this.browser.addEventListener('mousemove', this, true);
this.screen.addEventListener('mousemove', this, true);
this.treeStyleTab.tabStripPlaceHolder.addEventListener('mousemove', this, true);
this.treeStyleTab.tabStrip.addEventListener('mousemove', this, true);
this.mouseMoveListening = true;
this.notifyStatusToAllTabs();
},
endListenMouseMove : function AHB_endListenMouseMove()
{
if (!this.mouseMoveListening) return;
this.browser.removeEventListener('mousemove', this, true);
this.screen.removeEventListener('mousemove', this, true);
this.treeStyleTab.tabStripPlaceHolder.removeEventListener('mousemove', this, true);
this.treeStyleTab.tabStrip.removeEventListener('mousemove', this, true);
this.mouseMoveListening = false;
this.notifyStatusToAllTabs();
},
get shouldListenMouseMove()
@ -354,9 +375,9 @@ AutoHideBrowser.prototype = {
utils.getTreePref('tabbar.autoShow.tabSwitch');
},
showHideOnMouseMove : function AHB_showHideOnMouseMove(aEvent)
showHideOnMouseMove : function AHB_showHideOnMouseMove(aCoordinates)
{
var position = this.getMousePosition(aEvent);
var position = this.getMousePosition(aCoordinates);
if (position == this.MOUSE_POSITION_UNKNOWN)
return;
@ -400,7 +421,7 @@ AutoHideBrowser.prototype = {
b = null;
},
getMousePosition : function AHB_getMousePosition(aEvent)
getMousePosition : function AHB_getMousePosition(aCoordinates)
{
var w = this.window;
if ('gestureInProgress' in w && w.gestureInProgress)
@ -417,7 +438,7 @@ AutoHideBrowser.prototype = {
let resizable = !sv.fixed;
if (resizable &
this.widthFromMode > 24 &&
(clickable = this.getNearestClickableBox(aEvent))) {
(clickable = this.getNearestClickableBox(aCoordinates))) {
/* For resizing of shrunken tab bar and clicking closeboxes,
we have to shrink sensitive area. */
sensitiveArea = -(clickable.width + clickable.padding);
@ -430,24 +451,24 @@ AutoHideBrowser.prototype = {
if (
pos == 'left' ?
(aEvent.screenX > box.screenX + sensitiveArea) :
(aCoordinates.screenX > box.screenX + sensitiveArea) :
pos == 'right' ?
(aEvent.screenX < box.screenX + box.width - sensitiveArea) :
(aCoordinates.screenX < box.screenX + box.width - sensitiveArea) :
pos == 'bottom' ?
(aEvent.screenY < box.screenY + box.height - sensitiveArea) :
(aEvent.screenY > box.screenY + sensitiveArea)
(aCoordinates.screenY < box.screenY + box.height - sensitiveArea) :
(aCoordinates.screenY > box.screenY + sensitiveArea)
) {
return this.MOUSE_POSITION_OUTSIDE;
}
if (
pos == 'left' ?
(aEvent.screenX <= box.screenX - sensitiveArea) :
(aCoordinates.screenX <= box.screenX - sensitiveArea) :
pos == 'right' ?
(aEvent.screenX >= box.screenX + box.width + sensitiveArea) :
(aCoordinates.screenX >= box.screenX + box.width + sensitiveArea) :
pos == 'bottom' ?
(aEvent.screenY >= box.screenY + box.height + sensitiveArea) :
(aEvent.screenY <= box.screenY - sensitiveArea)
(aCoordinates.screenY >= box.screenY + box.height + sensitiveArea) :
(aCoordinates.screenY <= box.screenY - sensitiveArea)
) {
return this.MOUSE_POSITION_INSIDE;
}
@ -473,16 +494,16 @@ AutoHideBrowser.prototype = {
MOUSE_POSITION_INSIDE : (1 << 1),
MOUSE_POSITION_NEAR : (1 << 2),
MOUSE_POSITION_SENSITIVE : (1 << 1) | (1 << 2),
getNearestClickableBox : function AHB_getNearestClickableBox(aEvent)
getNearestClickableBox : function AHB_getNearestClickableBox(aCoordinates)
{
var sv = this.treeStyleTab;
var tab = sv.getTabFromCoordinates(aEvent);
var tab = sv.getTabFromCoordinates(aCoordinates);
if (!tab)
return null;
var position = sv.invertedScreenPositionProp;
var size = sv.invertedSizeProp;
var coordinate = aEvent[sv.invertedScreenPositionProp];
var coordinate = aCoordinates[sv.invertedScreenPositionProp];
var tabbox = tab.boxObject;
var closebox;
@ -720,7 +741,7 @@ AutoHideBrowser.prototype = {
this.contentAreaScreenEnabled &&
Services.focus.activeWindow &&
Services.focus.activeWindow.top == this.window &&
this.findPluginArea(this.browser.mCurrentBrowser.contentWindow)
this.hasPluginArea(this.browser.mCurrentBrowser.contentWindow)
) {
let box = this.getContentsAreaBox();
let style = this.screen.style;
@ -740,10 +761,15 @@ AutoHideBrowser.prototype = {
this.screen.hidePopup();
}
},
findPluginArea : function AHB_findPluginArea(aFrame)
hasPluginArea : function AHB_hasPluginArea(aFrame)
{
return aFrame.document.querySelector('embed, object') ||
Array.some(aFrame.frames, AHB_findPluginArea);
return (
aFrame && // Workaround. I have to make this work with e10s...
(
aFrame.document.querySelector('embed, object') ||
Array.some(aFrame.frames, AHB_hasPluginArea)
)
);
},
show : function AHB_show(aReason) /* PUBLIC API */
@ -1056,6 +1082,7 @@ AutoHideBrowser.prototype = {
var sv = this.treeStyleTab;
var w = this.window;
if (
aEvent.target &&
!this.isResizing &&
sv.evaluateXPath(
'ancestor-or-self::*[@class="'+sv.kSPLITTER+'"]',
@ -1071,12 +1098,17 @@ AutoHideBrowser.prototype = {
this.enabled &&
this.expanded &&
(
!aEvent.originalTarget ||
aEvent.originalTarget.ownerDocument != this.document ||
!sv.getTabBrowserFromChild(aEvent.originalTarget)
)
)
this.hide(this.kHIDDEN_BY_CLICK);
this.lastMouseDownTarget = aEvent.originalTarget.localName;
this.lastMouseDownTarget = (
aEvent.originalTargetLocalName ||
(aEvent.originalTarget && aEvent.originalTarget.localName) ||
''
);
},
onMouseUp : function AHB_onMouseUp(aEvent)
@ -1099,7 +1131,7 @@ AutoHideBrowser.prototype = {
{
var sv = this.treeStyleTab;
if (this.isResizing &&
/^(scrollbar|thumb|slider|scrollbarbutton)$/i.test(this.lastMouseDownTarget))
/^(scrollbar|thumb|slider|scrollbarbutton)$/i.test(this.lastMouseDownTarget || ''))
return true;
if (
@ -1282,7 +1314,7 @@ AutoHideBrowser.prototype = {
}
}
};
});
function AutoHideWindow(aWindow)
{

View File

@ -54,6 +54,7 @@ XPCOMUtils.defineLazyModuleGetter(this, 'FullTooltipManager', 'resource://treest
XPCOMUtils.defineLazyModuleGetter(this, 'TabbarDNDObserver', 'resource://treestyletab-modules/tabbarDNDObserver.js');
XPCOMUtils.defineLazyModuleGetter(this, 'TabpanelDNDObserver', 'resource://treestyletab-modules/tabpanelDNDObserver.js');
XPCOMUtils.defineLazyModuleGetter(this, 'AutoHideBrowser', 'resource://treestyletab-modules/autoHide.js');
XPCOMUtils.defineLazyModuleGetter(this, 'ContentBridge', 'resource://treestyletab-modules/contentBridge.js');
XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUIShowHideObserver', 'resource://treestyletab-modules/browserUIShowHideObserver.js');
XPCOMUtils.defineLazyGetter(this, 'window', function() {
@ -1000,6 +1001,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
if (!aTab.hasAttribute(this.kNEST))
aTab.setAttribute(this.kNEST, 0);
aTab.__treestyletab__contentBridge = new ContentBridge(aTab, this.mTabBrowser);
this.autoHide.notifyStatusToTab(aTab);
},
isTabInitialized : function TSTBrowser_isTabInitialized(aTab)
@ -1991,7 +1995,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
if (!collapsed && aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE)
setTimeout((function() {
this.scrollToTab(this.browser.selectedTab);
if (this.browser) // ignore calling after destroyed...
this.scrollToTab(this.browser.selectedTab);
}).bind(this), 0);
},
getTabbarPlaceholderSize: function TSTBrowser_getTabbarPlaceholderSize()
@ -2215,6 +2220,11 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
delete aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave;
}
this.autoHide.notifyStatusToTab(aTab);
aTab.__treestyletab__contentBridge.destroy();
delete aTab.__treestyletab__contentBridge;
delete aTab.__treestyletab__linkedTabBrowser;
},

View File

@ -202,5 +202,16 @@ const TreeStyleTabConstants = Object.freeze({
MAX_TABBAR_SIZE_RATIO : 0.8,
DEFAULT_SHRUNKEN_WIDTH_RATIO : 0.67,
MIN_TABBAR_WIDTH : 24,
MIN_TABBAR_HEIGHT : 24
MIN_TABBAR_HEIGHT : 24,
// CONTENT_SCRIPT : 'chrome://treestyletab/content/content-utils.js',
CONTENT_SCRIPT_AUTOHIDE : 'chrome://treestyletab/content/content-utils-autohide.js',
MESSAGE_TYPE : 'treestyletab',
COMMAND_SHUTDOWN : 'shutdown',
COMMAND_REPORT_MOUSEDOWN : 'report-mousedown',
COMMAND_REPORT_MOUSEUP : 'report-mouseup',
COMMAND_REPORT_MOUSEMOVE : 'report-mousemove',
COMMAND_NOTIFY_AUTOHIDE_STATUS : 'notify-autohide-status'
});

117
modules/contentBridge.js Normal file
View File

@ -0,0 +1,117 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Tree Style Tab.
*
* The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
* Portions created by the Initial Developer are Copyright (C) 2014
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ******/
const EXPORTED_SYMBOLS = ['ContentBridge'];
const DEBUG = false;
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
Cu.import('resource://treestyletab-modules/constants.js');
function ContentBridge(aTab, aTabBrowser)
{
this.init(aTab, aTabBrowser);
}
ContentBridge.prototype = inherit(TreeStyleTabConstants, {
mTab : null,
mTabBrowser : null,
init : function CB_init(aTab, aTabBrowser)
{
this.mTab = aTab;
this.mTabBrowser = aTabBrowser;
this.handleMessage = this.handleMessage.bind(this);
var manager = this.mTab.linkedBrowser.messageManager;
// manager.loadFrameScript(this.CONTENT_SCRIPT, true);
manager.loadFrameScript(this.CONTENT_SCRIPT_AUTOHIDE, true);
manager.addMessageListener(this.MESSAGE_TYPE, this.handleMessage);
},
destroy : function CB_destroy()
{
var manager = this.mTab.linkedBrowser.messageManager;
manager.removeMessageListener(this.MESSAGE_TYPE, this.handleMessage);
this.sendAsyncCommand(this.COMMAND_SHUTDOWN);
delete this.mTab;
delete this.mTabBrowser;
},
sendAsyncCommand : function CB_sendAsyncCommand(aCommandType, aCommandParams)
{
var manager = this.mTab.linkedBrowser.messageManager;
manager.sendAsyncMessage(this.MESSAGE_TYPE, {
command : aCommandType,
params : aCommandParams || {}
});
},
handleMessage : function CB_handleMessage(aMessage)
{
// dump(JSON.stringify(aMessage.json)+'\n');
switch (aMessage.json.command)
{
case this.COMMAND_REPORT_MOUSEDOWN:
let (fakeEvent = this.fixupEventCoordinates(aMessage.json.event)) {
this.mTabBrowser.treeStyleTab.autoHide.onMouseDown(fakeEvent);
}
return;
case this.COMMAND_REPORT_MOUSEUP:
let (fakeEvent = this.fixupEventCoordinates(aMessage.json.event)) {
this.mTabBrowser.treeStyleTab.autoHide.onMouseUp(fakeEvent);
}
return;
case this.COMMAND_REPORT_MOUSEMOVE:
let (fakeEvent = this.fixupEventCoordinates(aMessage.json.event)) {
this.mTabBrowser.treeStyleTab.autoHide.handleMouseMove(fakeEvent);
}
return;
}
},
fixupEventCoordinates : function CB_fixupEventCoordinates(aCoordinates)
{
var box = this.mTab.linkedBrowser.boxObject;
aCoordinates.screenX += box.screenX;
aCoordinates.screenY += box.screenY;
return aCoordinates;
}
});