diff --git a/LICENSE.txt b/LICENSE.txt index b981fa9..6e48d93 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -42,6 +42,9 @@ * Portions created by Marc Boullet are Copyright (C) 2003, * Marc Boullet. All Rights Reserved. * + * Some icons are by Yusuke Kamiyamane (http://p.yusukekamiyamane.com). + * Available under a Creative Commons Attribution 3.0 Unported License. + * * 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"), diff --git a/chrome/content/firegestures/browser.js b/chrome/content/firegestures/browser.js index 84beb1b..4dd13d1 100644 --- a/chrome/content/firegestures/browser.js +++ b/chrome/content/firegestures/browser.js @@ -105,6 +105,10 @@ var FireGestures = { case "wheel-down": case "rocker-left": case "rocker-right": + case "rocker-middle-left": + case "rocker-middle-right": + case "rocker-left-middle": + case "rocker-right-middle": case "keypress-ctrl": case "keypress-shift": this.onMouseGesture(event, aGesture); diff --git a/chrome/content/firegestures/prefs-generic.xul b/chrome/content/firegestures/prefs-generic.xul index a190a75..7f43bc5 100644 --- a/chrome/content/firegestures/prefs-generic.xul +++ b/chrome/content/firegestures/prefs-generic.xul @@ -46,9 +46,10 @@ - - - + + + + @@ -66,19 +67,21 @@ - - - + + + + + + + + + + + + + + - + + + + + + + diff --git a/chrome/locale/de/firegestures/prefs.dtd b/chrome/locale/de/firegestures/prefs.dtd index 910c7e1..ab05fb9 100644 --- a/chrome/locale/de/firegestures/prefs.dtd +++ b/chrome/locale/de/firegestures/prefs.dtd @@ -34,6 +34,12 @@ + + + + + + diff --git a/chrome/locale/en-US/firegestures/prefs.dtd b/chrome/locale/en-US/firegestures/prefs.dtd index 3c56dce..4f1399a 100644 --- a/chrome/locale/en-US/firegestures/prefs.dtd +++ b/chrome/locale/en-US/firegestures/prefs.dtd @@ -34,6 +34,12 @@ + + + + + + diff --git a/chrome/skin/classic/firegestures/prefs.css b/chrome/skin/classic/firegestures/prefs.css index f6aa9de..2201832 100644 --- a/chrome/skin/classic/firegestures/prefs.css +++ b/chrome/skin/classic/firegestures/prefs.css @@ -25,6 +25,45 @@ radio[pane][selected="true"] .paneButtonIcon { opacity: 1.0; } +image[id^="rocker"] { + list-style-image: url("chrome://firegestures/skin/rocker-gestures.png"); +} + +image[id^="wheel"] { + list-style-image: url("chrome://firegestures/skin/wheel-gestures.png"); +} + +label.button0 #wheelGestureUImage, +#rockerGestureLImage { + -moz-image-region: rect(0px, 32px, 16px, 0px); +} + +label.button0 #wheelGestureDImage, +#rockerGestureRImage { + -moz-image-region: rect(16px, 32px, 32px, 0px); +} + +label.button1 #wheelGestureUImage, +#rockerGestureMLImage { + -moz-image-region: rect(32px, 32px, 48px, 0px); +} + +label.button1 #wheelGestureDImage, +#rockerGestureMRImage { + -moz-image-region: rect(48px, 32px, 64px, 0px); +} + +label.button2 #wheelGestureUImage, +#rockerGestureLMImage { + -moz-image-region: rect(64px, 32px, 80px, 0px); +} + +label.button2 #wheelGestureDImage, +#rockerGestureRMImage { + -moz-image-region: rect(80px, 32px, 96px, 0px); +} + + #trailSampleOuter { background-color: white; min-height: 1.5em; diff --git a/chrome/skin/classic/firegestures/rocker-gestures.png b/chrome/skin/classic/firegestures/rocker-gestures.png new file mode 100755 index 0000000..5eb4586 Binary files /dev/null and b/chrome/skin/classic/firegestures/rocker-gestures.png differ diff --git a/chrome/skin/classic/firegestures/wheel-gestures.png b/chrome/skin/classic/firegestures/wheel-gestures.png new file mode 100755 index 0000000..fc7f072 Binary files /dev/null and b/chrome/skin/classic/firegestures/wheel-gestures.png differ diff --git a/components/xdGestureHandler.js b/components/xdGestureHandler.js index f977a17..5aef2ca 100644 --- a/components/xdGestureHandler.js +++ b/components/xdGestureHandler.js @@ -145,16 +145,17 @@ xdGestureHandler.prototype = { this._trailSize = getPref("mousetrail.size"); this._trailColor = getPref("mousetrail.color"); this._gestureTimeout = getPref("gesture_timeout"); - this._mouseGestureEnabled = getPref("mousegesture"); - this._wheelGestureEnabled = getPref("wheelgesture"); - this._rockerGestureEnabled = getPref("rockergesture"); - this._keypressGestureEnabled = getPref("keypressgesture"); + this._mouseGestureEnabled = getPref("mousegesture"); + this._wheelGestureEnabled = getPref("wheelgesture"); + this._rockerGestureEnabled = getPref("rockergesture"); + this._rockerGestureMiddleEnabled = getPref("rockergesture.middle"); + this._keypressGestureEnabled = getPref("keypressgesture"); // prefs for wheel gestures and rocker gestures this._drawArea.removeEventListener("DOMMouseScroll", this, true); this._drawArea.removeEventListener("click", this, true); if (this._wheelGestureEnabled) this._drawArea.addEventListener("DOMMouseScroll", this, true); - if (this._rockerGestureEnabled) + if (this._rockerGestureEnabled || this._rockerGestureMiddleEnabled) this._drawArea.addEventListener("click", this, true); // prefs for tab wheel gesture var tabbrowser = this._drawArea.ownerDocument.getBindingParent(this._drawArea); @@ -163,11 +164,15 @@ xdGestureHandler.prototype = { if (getPref("tabwheelgesture")) tabbrowser.mStrip.addEventListener("DOMMouseScroll", this._wheelOnTabBar, true); } + var prefSvc = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefBranch2) + .QueryInterface(Ci.nsIPrefService); + // if rocker gestures involving the middle mouse button are enabled, disable autoscroll + if (this._rockerGestureMiddleEnabled) { + prefSvc.setBoolPref("general.autoScroll", false); + } // if trigger button is middle, disable loading the clipboard URL with middle click. if (this._triggerButton == 1) { - var prefSvc = Cc["@mozilla.org/preferences-service;1"] - .getService(Ci.nsIPrefBranch2) - .QueryInterface(Ci.nsIPrefService); prefSvc.setBoolPref("middlemouse.contentLoadURL", false); // alert("middlemouse.contentLoadURL has been changed."); // #debug } @@ -178,12 +183,15 @@ xdGestureHandler.prototype = { _isMouseDownL: false, _isMouseDownM: false, _isMouseDownR: false, + _suppressClick: false, _suppressContext: false, _shouldFireContext: false, // [Linux] handleEvent: function FGH_handleEvent(event) { switch (event.type) { - case "mousedown": + case "mousedown": + // it seems that there is not always a click event, so avoid supressing regular clicks after rocker gestures + this._suppressClick = false; if (event.button == 0) { // suppress starting gesture on textboxes and textarea elements etc. var targetName = event.target.localName.toUpperCase(); @@ -198,7 +206,9 @@ xdGestureHandler.prototype = { break; } this._isMouseDownL = true; - this._isMouseDownM = false; // fixed invalid state of _isMouseDownM after autoscrolling + if (!this._rockerGestureMiddleEnabled) { + this._isMouseDownM = false; // fixed invalid state of _isMouseDownM after autoscrolling + } // any gestures with left-button - start if (this._triggerButton == 0 && !this._isMouseDownM && !this._isMouseDownR && !this._altKey(event)) { this._state = STATE_GESTURE; @@ -207,11 +217,15 @@ xdGestureHandler.prototype = { if (this._mouseGestureEnabled) event.preventDefault(); } - // rocker gesture + // rocker gestures else if (this._rockerGestureEnabled && this._isMouseDownR) { this._state = STATE_ROCKER; this._invokeExtraGesture(event, "rocker-left"); } + else if (this._rockerGestureMiddleEnabled && this._isMouseDownM) { + this._state = STATE_ROCKER; + this._invokeExtraGesture(event, "rocker-middle-left"); + } } else if (event.button == 1) { this._isMouseDownM = true; @@ -222,6 +236,15 @@ xdGestureHandler.prototype = { // prevent auto-scroll event.stopPropagation(); } + // rocker gestures + else if (this._rockerGestureMiddleEnabled && this._isMouseDownL) { + this._state = STATE_ROCKER; + this._invokeExtraGesture(event, "rocker-left-middle"); + } + else if (this._rockerGestureMiddleEnabled && this._isMouseDownR) { + this._state = STATE_ROCKER; + this._invokeExtraGesture(event, "rocker-right-middle"); + } } else if (event.button == 2) { // this fixes the problem: when showing context menu of a Flash movie, @@ -232,7 +255,9 @@ xdGestureHandler.prototype = { break; } this._isMouseDownR = true; - this._isMouseDownM = false; // fixed invalid state of _isMouseDownM after autoscrolling + if (!this._rockerGestureMiddleEnabled) { + this._isMouseDownM = false; // fixed invalid state of _isMouseDownM after autoscrolling + } this._suppressContext = false; // only time to reset _suppressContext flag this._enableContextMenu(true); // any gestures with right-button - start @@ -240,11 +265,15 @@ xdGestureHandler.prototype = { this._state = STATE_GESTURE; this._startGesture(event); } - // rocker gesture + // rocker gestures else if (this._rockerGestureEnabled && this._isMouseDownL) { this._state = STATE_ROCKER; this._invokeExtraGesture(event, "rocker-right"); } + else if (this._rockerGestureMiddleEnabled && this._isMouseDownM) { + this._state = STATE_ROCKER; + this._invokeExtraGesture(event, "rocker-middle-right"); + } } break; case "mousemove": @@ -285,6 +314,10 @@ xdGestureHandler.prototype = { this._isMouseDownR = false; // need additional | && this._state != STATE_READY| condition? if (!this._isMouseDownL && !this._isMouseDownM && !this._isMouseDownR) { + // suppress clicks after releasing the last button in a rocker gesture + if (this._state == STATE_ROCKER) { + this._suppressClick = true; + } // keypress gesture if (this._state == STATE_KEYPRESS) { this._state = STATE_READY; @@ -304,8 +337,9 @@ xdGestureHandler.prototype = { } break; case "contextmenu": - // [Linux] if right-click without holding left-button, display context menu artificially - if (!this._isMouseDownL && this._isMouseDownR) { + // [Linux] if right-click without holding left-button or middle-button, display context menu artificially + if (this._isMouseDownR && + !this._isMouseDownL && (!this._rockerGestureMiddleEnabled || !this._isMouseDownM)) { // #debug-begin log("*** display context menu artificially"); if (PLATFORM == "Windows_NT") @@ -327,8 +361,8 @@ xdGestureHandler.prototype = { } break; case "DOMMouseScroll": - // mouse geture > wheel gesture / wheel gesture > wheel gesture - if (this._state == STATE_GESTURE || this._state == STATE_WHEEL) { + // (mouse|rocker|wheel) gesture > wheel gesture + if (this._state == STATE_GESTURE || this._state == STATE_WHEEL || this._state == STATE_ROCKER) { this._state = STATE_WHEEL; this._invokeExtraGesture(event, event.detail < 0 ? "wheel-up" : "wheel-down"); // suppress page scroll @@ -340,7 +374,8 @@ xdGestureHandler.prototype = { case "click": // this fixes the bug: performing rocker-left on a link causes visiting the link // need 'if (this._isMouseDownL || this._isMouseDownR)' condition? - if (this._state == STATE_ROCKER) { + if (this._state == STATE_ROCKER || this._suppressClick) { + this._suppressClick = false; event.preventDefault(); event.stopPropagation(); } diff --git a/defaults/preferences/firegestures-prefs.js b/defaults/preferences/firegestures-prefs.js index 62abf6c..e250412 100644 --- a/defaults/preferences/firegestures-prefs.js +++ b/defaults/preferences/firegestures-prefs.js @@ -1,6 +1,7 @@ pref("extensions.firegestures.mousegesture", true); pref("extensions.firegestures.wheelgesture", true); pref("extensions.firegestures.rockergesture", false); +pref("extensions.firegestures.rockergesture.middle", false); pref("extensions.firegestures.keypressgesture", true); pref("extensions.firegestures.tabwheelgesture", false); pref("extensions.firegestures.trigger_button", 2); diff --git a/source/rocker-wheel-gestures.psd b/source/rocker-wheel-gestures.psd new file mode 100755 index 0000000..84becec Binary files /dev/null and b/source/rocker-wheel-gestures.psd differ