Bug 1283299 - Part 10: Disable tabs in titlebar on GTK versions before 3.20. r?karlt draft
authorAndrew Comminos <andrew@comminos.com>
Tue, 05 Jul 2016 16:47:38 -0400
changeset 384227 6ce569259603
parent 384226 9cacb2b9314e
child 524649 904b1a652503
push id22212
push userbmo:andrew@comminos.com
push dateTue, 05 Jul 2016 20:52:16 +0000
reviewerskarlt
bugs1283299
milestone50.0a1
Bug 1283299 - Part 10: Disable tabs in titlebar on GTK versions before 3.20. r?karlt MozReview-Commit-ID: mPZap9MwAM
browser/base/content/browser-tabsintitlebar.js
browser/themes/linux/browser.css
dom/base/nsGkAtomList.h
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsMediaFeatures.cpp
widget/LookAndFeel.h
widget/gtk/nsLookAndFeel.cpp
widget/gtk/nsLookAndFeel.h
widget/gtk/nsWindow.cpp
--- a/browser/base/content/browser-tabsintitlebar.js
+++ b/browser/base/content/browser-tabsintitlebar.js
@@ -9,16 +9,21 @@
 var TabsInTitlebar = {
   init: function () {
     if (this._initialized) {
       return;
     }
     this._readPref();
     Services.prefs.addObserver(this._prefName, this, false);
 
+    // Always disable on unsupported GTK versions.
+    if (AppConstants.MOZ_WIDGET_TOOLKIT == "gtk3") {
+      this.allowedBy("gtk", window.matchMedia("(-moz-gtk-csd-available)"));
+    }
+
     // We need to update the appearance of the titlebar when the menu changes
     // from the active to the inactive state. We can't, however, rely on
     // DOMMenuBarInactive, because the menu fires this event and then removes
     // the inactive attribute after an event-loop spin.
     //
     // Because updating the appearance involves sampling the heights and margins
     // of various elements, it's important that the layout be more or less
     // settled before updating the titlebar. So instead of listening to
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1942,49 +1942,57 @@ notification.pluginVulnerable > .notific
 }
 
 .menuitem-iconic[usercontextid] > .menu-iconic-left > .menu-iconic-icon {
   visibility: visible;
 }
 
 /* Titlebar/CSD */
 
-#main-window[tabsintitlebar][sizemode="normal"] {
-  -moz-appearance: -moz-gtk-window-decoration;
-  background-color: transparent;
-  background-clip: border-box;
-  background-origin: border-box;
-}
-
-#main-window[tabsintitlebar][sizemode="normal"]:not([customizing]):not(:-moz-lwtheme) > #titlebar {
-  -moz-appearance: -moz-window-titlebar;
-}
-
-#main-window[tabsintitlebar][sizemode="maximized"]:not([customizing]):not(:-moz-lwtheme) > #titlebar {
-  -moz-appearance: -moz-window-titlebar-maximized;
-}
-
-#main-window[tabsintitlebar]:not([sizemode="fullscreen"]) #TabsToolbar {
-  -moz-appearance: none;
+@media not all and (-moz-gtk-csd-available) {
+  #main-window > #titlebar {
+    /* We need to hide the titlebar explicitly on versions of GTK without CSD. */
+    display: none;
+  }
 }
 
-/* titlebar command buttons */
+@media (-moz-gtk-csd-available) {
+  #main-window[tabsintitlebar][sizemode="normal"] {
+    -moz-appearance: -moz-gtk-window-decoration;
+    background-color: transparent;
+    background-clip: border-box;
+    background-origin: border-box;
+  }
+
+  #main-window[tabsintitlebar][sizemode="normal"]:not([customizing]):not(:-moz-lwtheme) > #titlebar {
+    -moz-appearance: -moz-window-titlebar;
+  }
+
+  #main-window[tabsintitlebar][sizemode="maximized"]:not([customizing]):not(:-moz-lwtheme) > #titlebar {
+    -moz-appearance: -moz-window-titlebar-maximized;
+  }
+
+  #main-window[tabsintitlebar]:not([sizemode="fullscreen"]) #TabsToolbar {
+    -moz-appearance: none;
+  }
 
-#titlebar-min {
-  list-style-image: url("moz-icon://stock/window-minimize-symbolic?size=menu");
-  -moz-appearance: -moz-window-button-minimize;
-}
+  /* titlebar command buttons */
+
+  #titlebar-min {
+    list-style-image: url("moz-icon://stock/window-minimize-symbolic?size=menu");
+    -moz-appearance: -moz-window-button-minimize;
+  }
 
-#titlebar-max {
-  list-style-image: url("moz-icon://stock/window-maximize-symbolic?size=menu");
-  -moz-appearance: -moz-window-button-maximize;
+  #titlebar-max {
+    list-style-image: url("moz-icon://stock/window-maximize-symbolic?size=menu");
+    -moz-appearance: -moz-window-button-maximize;
+  }
+
+  #main-window[sizemode="maximized"] #titlebar-max {
+    list-style-image: url("moz-icon://stock/window-restore-symbolic?size=menu");
+    -moz-appearance: -moz-window-button-restore;
+  }
+
+  #titlebar-close {
+    list-style-image: url("moz-icon://stock/window-close-symbolic?size=menu");
+    -moz-appearance: -moz-window-button-close;
+  }
 }
-
-#main-window[sizemode="maximized"] #titlebar-max {
-  list-style-image: url("moz-icon://stock/window-restore-symbolic?size=menu");
-  -moz-appearance: -moz-window-button-restore;
-}
-
-#titlebar-close {
-  list-style-image: url("moz-icon://stock/window-close-symbolic?size=menu");
-  -moz-appearance: -moz-window-button-close;
-}
-
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -2216,16 +2216,17 @@ GK_ATOM(mac_graphite_theme, "mac-graphit
 GK_ATOM(mac_lion_theme, "mac-lion-theme")
 GK_ATOM(mac_yosemite_theme, "mac-yosemite-theme")
 GK_ATOM(windows_compositor, "windows-compositor")
 GK_ATOM(windows_glass, "windows-glass")
 GK_ATOM(touch_enabled, "touch-enabled")
 GK_ATOM(menubar_drag, "menubar-drag")
 GK_ATOM(swipe_animation_enabled, "swipe-animation-enabled")
 GK_ATOM(physical_home_button, "physical-home-button")
+GK_ATOM(gtk_csd_available, "gtk-csd-available")
 
 // windows theme selector metrics
 GK_ATOM(windows_classic, "windows-classic")
 GK_ATOM(windows_theme_aero, "windows-theme-aero")
 GK_ATOM(windows_theme_aero_lite, "windows-theme-aero-lite")
 GK_ATOM(windows_theme_luna_blue, "windows-theme-luna-blue")
 GK_ATOM(windows_theme_luna_olive, "windows-theme-luna-olive")
 GK_ATOM(windows_theme_luna_silver, "windows-theme-luna-silver")
@@ -2254,16 +2255,17 @@ GK_ATOM(_moz_windows_theme, "-moz-window
 GK_ATOM(_moz_os_version, "-moz-os-version")
 GK_ATOM(_moz_touch_enabled, "-moz-touch-enabled")
 GK_ATOM(_moz_menubar_drag, "-moz-menubar-drag")
 GK_ATOM(_moz_device_pixel_ratio, "-moz-device-pixel-ratio")
 GK_ATOM(_moz_device_orientation, "-moz-device-orientation")
 GK_ATOM(_moz_is_resource_document, "-moz-is-resource-document")
 GK_ATOM(_moz_swipe_animation_enabled, "-moz-swipe-animation-enabled")
 GK_ATOM(_moz_physical_home_button, "-moz-physical-home-button")
+GK_ATOM(_moz_gtk_csd_available, "-moz-gtk-csd-available")
 
 // application commands
 GK_ATOM(Back, "Back")
 GK_ATOM(Forward, "Forward")
 GK_ATOM(Reload, "Reload")
 GK_ATOM(Stop, "Stop")
 GK_ATOM(Search, "Search")
 GK_ATOM(Bookmarks, "Bookmarks")
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1177,16 +1177,22 @@ InitSystemMetrics()
   }
 
   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_PhysicalHomeButton,
                            &metricResult);
   if (NS_SUCCEEDED(rv) && metricResult) {
     sSystemMetrics->AppendElement(nsGkAtoms::physical_home_button);
   }
 
+  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDAvailable,
+                           &metricResult);
+  if (NS_SUCCEEDED(rv) && metricResult) {
+    sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_available);
+  }
+
 #ifdef XP_WIN
   if (NS_SUCCEEDED(
         LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsThemeIdentifier,
                             &metricResult))) {
     nsCSSRuleProcessor::SetWindowsThemeIdentifier(static_cast<uint8_t>(metricResult));
     switch(metricResult) {
       case LookAndFeel::eWindowsTheme_Aero:
         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_aero);
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -802,16 +802,25 @@ nsMediaFeatures::features[] = {
     &nsGkAtoms::_moz_physical_home_button,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
     nsMediaFeature::eNoRequirements,
     { &nsGkAtoms::physical_home_button },
     GetSystemMetric
   },
 
+  {
+    &nsGkAtoms::_moz_gtk_csd_available,
+    nsMediaFeature::eMinMaxNotAllowed,
+    nsMediaFeature::eBoolInteger,
+    nsMediaFeature::eNoRequirements,
+    { &nsGkAtoms::gtk_csd_available },
+    GetSystemMetric
+  },
+
   // Internal -moz-is-glyph media feature: applies only inside SVG glyphs.
   // Internal because it is really only useful in the user agent anyway
   //  and therefore not worth standardizing.
   {
     &nsGkAtoms::_moz_is_glyph,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
     nsMediaFeature::eNoRequirements,
--- a/widget/LookAndFeel.h
+++ b/widget/LookAndFeel.h
@@ -393,16 +393,22 @@ public:
     /*
      * A boolean value indicating whether or not the device has a hardware
      * home button. Used on gaia to determine whether a home button
      * is shown.
      */
      eIntID_PhysicalHomeButton,
 
      /*
+      * A boolean value indicating whether client-side decorations are
+      * supported by the user's GTK version.
+      */
+     eIntID_GTKCSDAvailable,
+
+     /*
       * Controls whether overlay scrollbars display when the user moves
       * the mouse in a scrollable frame.
       */
      eIntID_ScrollbarDisplayOnMouseMove,
 
      /*
       * Overlay scrollbar animation constants.
       */
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -801,16 +801,19 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
         break;
     case eIntID_ColorPickerAvailable:
         aResult = 1;
         break;
     case eIntID_ContextMenuOffsetVertical:
     case eIntID_ContextMenuOffsetHorizontal:
         aResult = 2;
         break;
+    case eIntID_GTKCSDAvailable:
+        aResult = sCSDAvailable;
+        break;
     default:
         aResult = 0;
         res     = NS_ERROR_FAILURE;
     }
 
     return res;
 }
 
@@ -1397,16 +1400,21 @@ nsLookAndFeel::Init()
     sInvisibleCharacter = char16_t(value);
 
     // caret styles
     gtk_widget_style_get(entry,
                          "cursor-aspect-ratio", &sCaretRatio,
                          nullptr);
 
     gtk_widget_destroy(window);
+
+    // Require GTK 3.20 for client-side decoration support.
+    // 3.20 exposes gtk_render_background_get_clip, which is required for
+    // calculating shadow metrics for decorated windows.
+    sCSDAvailable = gtk_check_version(3, 20, 0) == nullptr;
 }
 
 // virtual
 char16_t
 nsLookAndFeel::GetPasswordCharacterImpl()
 {
     return sInvisibleCharacter;
 }
--- a/widget/gtk/nsLookAndFeel.h
+++ b/widget/gtk/nsLookAndFeel.h
@@ -25,16 +25,18 @@ public:
     virtual bool GetFontImpl(FontID aID, nsString& aFontName,
                              gfxFontStyle& aFontStyle,
                              float aDevPixPerCSSPixel);
 
     virtual void RefreshImpl();
     virtual char16_t GetPasswordCharacterImpl();
     virtual bool GetEchoPasswordImpl();
 
+    bool IsCSDAvailable() const { return sCSDAvailable; }
+
 protected:
 #if (MOZ_WIDGET_GTK == 2)
     struct _GtkStyle *mStyle;
 #else
     struct _GtkStyleContext *mBackgroundStyle;
     struct _GtkStyleContext *mButtonStyle;
 #endif
 
@@ -79,13 +81,14 @@ protected:
     nscolor sTextSelectedBackground;
     nscolor sMozScrollbar;
 #if (MOZ_WIDGET_GTK == 3)
     nscolor sInfoBarText;
 #endif
     char16_t sInvisibleCharacter;
     float   sCaretRatio;
     bool    sMenuSupportsDrag;
+    bool    sCSDAvailable;
 
     void Init();
 };
 
 #endif
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -76,16 +76,17 @@
 #include "nsGtkUtils.h"
 #include "nsIObserverService.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "nsIIdleServiceInternal.h"
 #include "nsIPropertyBag2.h"
 #include "GLContext.h"
 #include "gfx2DGlue.h"
 #include "nsPluginNativeWindowGtk.h"
+#include "nsLookAndFeel.h"
 
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/Accessible.h"
 #include "mozilla/a11y/Platform.h"
 #include "nsAccessibilityService.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
@@ -6942,16 +6943,21 @@ nsWindow::SetNonClientMargins(LayoutDevi
 }
 
 void
 nsWindow::SetDrawsInTitlebar(bool aState)
 {
   if (aState == mDrawsInTitlebar)
     return;
 
+  if (aState && !nsXPLookAndFeel::GetInstance()->IsCSDAvailable()) {
+    NS_WARNING("Client side decorations unsupported, ignoring.");
+    return;
+  }
+
   if (mShell) {
     NS_WARNING("gtk_window_set_decorated may not have any effect when called on a window that is already visible.");
     gtk_window_set_decorated(GTK_WINDOW(mShell), !aState);
   }
 
   mDrawsInTitlebar = aState;
 
   UpdateClientShadowWidth();