Bug 1364896 - Part 2 - Increase margin of all context menus that are triggered through touch. r=dao draft
authorJohann Hofmann <jhofmann@mozilla.com>
Fri, 09 Jun 2017 14:47:50 +0200
changeset 600794 8bbf0390a2c0dc82cfe6bb073ee0e6447f4afc81
parent 600793 4f2cacf2e8b603bc206595a1f5e5c15b7ea04bd0
child 600795 e59df4f487f60cea137fbf8aea71a854a5706de9
push id65882
push userbmo:jhofmann@mozilla.com
push dateTue, 27 Jun 2017 21:08:20 +0000
reviewersdao
bugs1364896
milestone56.0a1
Bug 1364896 - Part 2 - Increase margin of all context menus that are triggered through touch. r=dao MozReview-Commit-ID: ISc3ZyS1njY
browser/base/content/browser.js
browser/base/content/nsContextMenu.js
browser/themes/windows/browser.css
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1629,16 +1629,20 @@ var gBrowserInit = {
     LightWeightThemeWebInstaller.init();
 
     if (Win7Features)
       Win7Features.onOpenWindow();
 
     FullScreen.init();
     PointerLock.init();
 
+    if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
+      ContextMenuTouchModeObserver.init();
+    }
+
     // initialize the sync UI
     gSync.init();
 
     if (AppConstants.MOZ_DATA_REPORTING)
       gDataNotificationInfoBar.init();
 
     gBrowserThumbnails.init();
 
@@ -1838,16 +1842,19 @@ var gBrowserInit = {
       } catch (ex) {
         Cu.reportError(ex);
       }
 
       if (this.gmpInstallManager) {
         this.gmpInstallManager.uninit();
       }
 
+      if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
+        ContextMenuTouchModeObserver.uninit();
+      }
       BrowserOffline.uninit();
       IndexedDBPromptHelper.uninit();
       PanelUI.uninit();
       AutoShowBookmarksToolbar.uninit();
     }
 
     // Final window teardown, do this last.
     window.XULBrowserWindow = null;
@@ -8214,16 +8221,87 @@ var RestoreLastSessionObserver = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference])
 };
 
 function restoreLastSession() {
   SessionStore.restoreLastSession();
 }
 
+/* Observes context menus and adjusts their size for better
+ * usability when opened via a touch screen. */
+var ContextMenuTouchModeObserver = {
+  get _searchBarContextMenu() {
+    let searchbar = document.getElementById("searchbar");
+    let textBox = document.getAnonymousElementByAttribute(searchbar,
+                                        "anonid", "searchbar-textbox");
+    let inputBox = document.getAnonymousElementByAttribute(textBox,
+                                        "anonid", "textbox-input-box");
+    let menu = document.getAnonymousElementByAttribute(inputBox,
+                                        "anonid", "input-box-contextmenu");
+    return menu;
+  },
+
+  get _urlBarContextMenu() {
+    let urlbar = document.getElementById("urlbar");
+    let textBox = document.getAnonymousElementByAttribute(urlbar,
+                                        "anonid", "textbox-input-box");
+    let menu = document.getAnonymousElementByAttribute(textBox,
+                                        "anonid", "input-box-contextmenu");
+    return menu;
+  },
+
+  _addListener(el) {
+    el.addEventListener("popupshowing", this);
+  },
+
+  _removeListener(el) {
+    el.removeEventListener("popupshowing", this);
+  },
+
+  init() {
+    // Start observing different context menus for popupshowing.
+
+    // The main popup set, which contains several context menus,
+    // e.g. the page content area context menu.
+    this._addListener(document.getElementById("mainPopupSet"));
+
+    // The navigation context menu of the back and forward button.
+    this._addListener(document.getElementById("back-button"));
+    this._addListener(document.getElementById("forward-button"));
+
+    // The search bar context menu.
+    this._addListener(this._searchBarContextMenu);
+
+    // The url bar context menu.
+    this._addListener(this._urlBarContextMenu);
+  },
+
+  handleEvent(event) {
+    let target = event.target;
+    if (target.localName != "menupopup") {
+      return;
+    }
+
+    if (event.mozInputSource == MouseEvent.MOZ_SOURCE_TOUCH) {
+      target.setAttribute("touchmode", "true");
+    } else {
+      target.removeAttribute("touchmode");
+    }
+  },
+
+  uninit() {
+    this._removeListener(document.getElementById("mainPopupSet"));
+    this._removeListener(document.getElementById("back-button"));
+    this._removeListener(document.getElementById("forward-button"));
+    this._removeListener(this._searchBarContextMenu);
+    this._removeListener(this._urlBarContextMenu);
+  },
+};
+
 var TabContextMenu = {
   contextTab: null,
   _updateToggleMuteMenuItem(aTab, aConditionFn) {
     ["muted", "soundplaying"].forEach(attr => {
       if (!aConditionFn || aConditionFn(attr)) {
         if (aTab.hasAttribute(attr)) {
           aTab.toggleMuteMenuItem.setAttribute(attr, "true");
         } else {
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -57,24 +57,24 @@ function openContextMenu(aMessage) {
                               disableSetDesktopBackground: data.disableSetDesktopBg,
                               loginFillInfo: data.loginFillInfo,
                               parentAllowsMixedContent: data.parentAllowsMixedContent,
                               userContextId: data.userContextId,
                             };
   let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
   let event = gContextMenuContentData.event;
 
-  // Set touch mode to get larger menu items.
-  if (event.mozInputSource == MouseEvent.MOZ_SOURCE_TOUCH) {
-    popup.setAttribute("touchmode", "true");
-  } else {
-    popup.removeAttribute("touchmode");
-  }
+  // The event is a CPOW that can't be passed into the native openPopupAtScreen
+  // function. Therefore we synthesize a new MouseEvent to propagate the
+  // inputSource to the subsequently triggered popupshowing event.
+  var newEvent = document.createEvent("MouseEvent");
+  newEvent.initNSMouseEvent("contextmenu", true, true, null, 0, event.screenX, event.screenY,
+                            0, 0, false, false, false, false, 0, null, 0, event.mozInputSource);
 
-  popup.openPopupAtScreen(event.screenX, event.screenY, true);
+  popup.openPopupAtScreen(newEvent.screenX, newEvent.screenY, true, newEvent);
 }
 
 function nsContextMenu(aXulMenu, aIsShift) {
   this.shouldDisplay = true;
   this.initMenu(aXulMenu, aIsShift);
 }
 
 // Prototype for nsContextMenu "class."
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1965,18 +1965,18 @@ notification.pluginVulnerable > .notific
   margin-left: -10px;
   margin-right: -10px;
   margin-bottom: -10px;
 }
 
 %include ../shared/contextmenu.inc.css
 
 /* Make context menu items larger when opened through touch. */
-#contentAreaContextMenu[touchmode] menu,
-#contentAreaContextMenu[touchmode] menuitem {
+menupopup[touchmode] menu,
+menupopup[touchmode] menuitem {
   padding-top: 12px;
   padding-bottom: 12px;
 }
 
 #contentAreaContextMenu[touchmode] > #context-navigation > menuitem {
   padding-top: 7px;
   padding-bottom: 7px;
 }